1 Introduction

Bulk RNA sequencing data on 24 pre-treatment breast cancer tumours performed by Wu et al. [1] was downloaded from GEO with accession GSE176078, and associated publication.

geo_id <- "GSE176078"

This dataset was sequenced using Illumina NextSeq 500 (Homo sapiens), submitted on Apr 15 2014.

Breast cancers are clinically stratified based on:

  • expression of the estrogen receptor (ER),
  • expression of the progesterone receptor (PR), and
  • overexpression of HER2 (or amplification of HER2 gene ERBB2)

This results in the following three clinical subtypes within this dataset:

  • Luminal ie. ER+; (ER+, PR+/-)
  • HER2+; (HER2+, ER+/-, PR+/-)
  • Triple Negative ie. TNBC; (ER-, PR-, HER2-)

Breast cancers are also stratified on bulk transcriptomic profiling via PAM50 gene signatures [2] describing five molecular subtypes: Luminal A, Luminal B, HER2-enriched, Basal-like, and Normal-like.

The ~70-80% concordance between clinical and molecular subtypes motivated this study to improve functional understanding of breast cancer in a broader and more coherent sense.

For this study, the clinical subtype conditions classified are as follows:

  • HER2+ ; (HER2+, ER-, PR+/-)
  • HER2+/ER+ ; (HER2+, ER+, PR+/-)
  • ER+ ; (HER2-, ER+, PR+/-)
  • TNBC ; (HER2-, ER-, PR-)

The distribution of clinical subtypes across the 24 samples is shown in table 1.

Table 1: Clinical breast cancer subtype splits in our dataset
Count Percent
HER2+ 2 8.33
HER2+/ER+ 2 8.33
TNBC 8 33.33
ER+ 12 50.00
Total 24 100.00

This leads to

  • 16.6666667% of samples containing HER2 expression, and
  • 58.3333333% of samples containing ER expression,

With the overlaps giving us

  • 50% of those with HER2 expressed also had ER expressed,
  • 14.2857143% of those with ER expressed also had HER2 expressed.

The raw counts were cleaned, mapped to HUGO Gene Nomenclature Committee (HGNC) Symbols, and normalized to produce final counts. Of the original 58387 genes, we were able to map and produce 28712 unversioned, unique genes, of which filtering outliers (keeping genes present in a minimum of 12 samples) resulted in 14800 genes remaining.

The density plot shows the distribution of the cleaned, filtered, and normalized counts per million across all samples (varying colours).


Figure 1: Smoothing density of filtered and normalized CPM counts for 24 samples across four clinical subtypes of breast cancer tissue. Counts were filtered with edgeR’s cpm() thresholded at a minimum sum of 12 CPM across samples for each gene. Counts were normalized with edgeR’s DGEList() across all four clinical subtypes. Normalization factors were calculated via TMM.
Figure 1: Smoothing density of filtered and normalized CPM counts for 24 samples across four clinical subtypes of breast cancer tissue. Counts were filtered with edgeR’s cpm() thresholded at a minimum sum of 12 CPM across samples for each gene. Counts were normalized with edgeR’s DGEList() across all four clinical subtypes. Normalization factors were calculated via TMM.


Dispersion was calculated using edgeR to describe deviation of variance from the mean. The Biological Coefficient of Variation (BCV) is dispersion-squared, and represents the mean-variance relationship among genes.

Figure 2: Biological Coefficient of Variation (Dispersion squared) for 24 samples across four clinical subtypes of breast cancer tissue gene-wise. Dispersion was calculated using edgeR’s plotBCV() on the model designed across all four clinical subtypes.
Figure 2: Biological Coefficient of Variation (Dispersion squared) for 24 samples across four clinical subtypes of breast cancer tissue gene-wise. Dispersion was calculated using edgeR’s plotBCV() on the model designed across all four clinical subtypes.


The normalized counts were modeled by two designs. The first being an aggregate design considering all clinical subtypes as distinct, ie. HER2+/ER+, HER2+, ER+, and TNBC. The second being a split binary-pairing model combining the two separate classification subtypes, ie. HER2+/- and ER+/- as a binary pair. The separate model designs represented different perspectives on labeling the data and allow for more specific or generic conclusions.

# aggregate model design
model_design <- model.matrix(~ types_df$subtype)

# split model design (binary pairs)
splt_model_design <- model.matrix(~ types_df$her2 + types_df$er)

The Quasi-Likelihood Model from edgeR was used to produce Quasi-Likelihood Fits for each model design, at which point differential expression was calculated across the models.

# normalized counts grouped by clinical subtype
d <- DGEList(counts=norm_matrix, 
             group=types_df$subtype)

# estimate dispersion on subtype model design
d_ <- estimateDisp(d, model_design)
qlfit <- glmQLFit(d_, model_design)

# in parallel, estimate dispersion on binary pairing model design
d_splt <- estimateDisp(d, splt_model_design)
qlfit_splt <- glmQLFit(d_splt, splt_model_design)

# fit subtype model design
qlf.subtypes <- glmQLFTest(qlfit)

# fit split model design
qlf.her2p <- glmQLFTest(qlfit_splt, 
                        coef='types_df$erTRUE')
qlf.erp <- glmQLFTest(qlfit_splt, 
                      coef='types_df$her2TRUE')

The Benjamini-Hochberg method for false discovery was used to correct p-values to classify the resulting genes that passed correction for differential expression in their respective models, producing the following volcano plots. Note that only the aggregate design and ER specific expression models are shown since no genes passed correction for the HER2 specific design.

Figure 3: Volcano Plot for significantly differentially expressed genes in 24 samples across four clinical subtypes of breast cancer tissue (aggregate design). Differential expression was calculated across the aggregate model design across all four clinical subtypes. Significant before correction is represented by p < 0.05, with significant after correction being FDR < 0.05.
Figure 3: Volcano Plot for significantly differentially expressed genes in 24 samples across four clinical subtypes of breast cancer tissue (aggregate design). Differential expression was calculated across the aggregate model design across all four clinical subtypes. Significant before correction is represented by p < 0.05, with significant after correction being FDR < 0.05.


The aggregate model highlights in red CD207, MKX, and ANXA8 as genes significantly differentially expressed after correction for false discovery.

Figure 4: Volcano Plot for significantly differentially expressed genes in 24 samples across binary over-expression of ER clinical subtypes of breast cancer tissue (split design). Differential expression was calculated across ER expression design. Significant before correction is represented by p < 0.05, with significant after correction being FDR < 0.05.
Figure 4: Volcano Plot for significantly differentially expressed genes in 24 samples across binary over-expression of ER clinical subtypes of breast cancer tissue (split design). Differential expression was calculated across ER expression design. Significant before correction is represented by p < 0.05, with significant after correction being FDR < 0.05.


The split model in terms of ER over-expression highlights in red EPHA3, KCNMB2, CLEC1B, CYP2G1P, CDH26, CASC3, TFF3, RAPGEFL1, MSL1, MUC4, and THRA as genes significantly differentially expressed after correction for false discovery.

Using these models, non-thresholded gene-sets can be pulled by ranking according to -log(p-values) and signing according to the log fold-change.

# create non-thresholded gene sets

# across all clinical subtypes
nt_geneset <- qlf.subtypes$table
nt_geneset[,"Rank"] <- -log10(nt_geneset$PValue) * sign(nt_geneset$logFC)
nt_geneset <- nt_geneset[order(nt_geneset$Rank, decreasing=TRUE),]

# across ER over-expression
er_geneset <- qlf.erp$table
er_geneset[,"Rank"] <- -log10(er_geneset$PValue) * sign(er_geneset$logFC)
er_geneset <- er_geneset[order(er_geneset$Rank, decreasing=TRUE),]

The ranked gene-sets are saved as .rnk files for further analysis in the remainder of this report.

# for the aggregate clinical subtype model
# create a separate ranks matrix with only gene name and rank
geneset_ranks <- cbind(rownames(nt_geneset), nt_geneset[,"Rank"])
colnames(geneset_ranks) <- c("GeneName", "Rank")

ranked_geneset_filepath <- file.path(getwd(), 
                                     geo_id, 
                                     "ag_ranks.rnk")
# if the file does not exist already
if (!file.exists(ranked_geneset_filepath)) {
  # write this matrix to the file
  write.table(geneset_ranks,
              ranked_geneset_filepath,
              quote=FALSE,sep="\t",row.name=FALSE)
}

# for the ER over-expression model
# create a separate ranks matrix with only gene name and rank
geneset_er_ranks <- cbind(rownames(er_geneset), er_geneset[,"Rank"])
colnames(geneset_er_ranks) <- c("GeneName", "Rank")

ranked_er_geneset_filepath <- file.path(getwd(), 
                                     geo_id, 
                                     "er_ranks.rnk")
# if the file does not exist already
if (!file.exists(ranked_er_geneset_filepath)) {
  # write this matrix to the file
  write.table(geneset_er_ranks,
              ranked_er_geneset_filepath,
              quote=FALSE,sep="\t",row.name=FALSE)
}
Table 2: Gene Ranks for aggregate model design across HER2+/ER+, HER2+, ER+, and TNBC clinical subtypes of breast cancer.
GeneName Rank
CD207 5.42322474118346
MKX 5.39993135731511
ANXA8 5.12680098507216
HES4 4.03194218398041
PCSK1 3.99254046943472
UCA1 3.73274435594156
Table 3: Gene Ranks for split model design across ER +/- overexpression as a clinical subtype classifier of breast cancer.
GeneName Rank
EPHA3 7.40069275730718
KCNMB2 6.31726250155973
CLEC1B 6.10558550086033
CYP2G1P 5.80136230063012
CDH26 5.28827272752202
CASC3 5.10530649248159

The first five genes are displayed in the tables above for the two model designs of interest.

2 Non-Thresholded Gene-Set Enrichment Analysis

Using the GSEA command-line interface .jar for compatibility of using GSEA with R, we can download the desired gene-set file from the Bader Lab.

The code below is adapted from Ruth Isserlin [3].

# variable names for easier modification
gsea_jar = "~/GSEA_4.3.2/gsea-cli.sh"
working_dir = "~/projects/GSE176078"
output_dir = "~/projects/GSE176078/gsea"
analysis_name_ag = "clinical subtypes"
analysis_name_er = "ER over-expression"
ag_rnk_file = "ag_ranks.rnk"
er_rnk_file = "er_ranks.rnk"

# the March 1st release (latest at this point)
gmt_url = "http://download.baderlab.org/EM_Genesets/March_01_2025/Human/symbol/"

#use the non-filtered gmt
gmt_files <- list.files(path = output_dir, pattern = "\\.gmt")
if (length(gmt_files) == 0) {
  # download the desired gene-set file
  filenames = getURL(gmt_url)
  tc = textConnection(filenames)
  contents = readLines(tc)
  close(tc)
    
  # filter based on the following specifications:
  # + Gene Ontology : Biological Processes terms, 
  #   + include All Pathways
  # - WikiPathways (PFOCR), and
  # - GO IEA (electronic annotations)
  rx = gregexpr("(?<=<a href=\")(.*.GOBP_AllPathways_noPFOCR_no_GO_iea.*.)(.gmt)(?=\">)",
                  contents, perl = TRUE)
  gmt_file = unlist(regmatches(contents, rx))
  
  dest_gmt_file <- file.path(output_dir, gmt_file)
    
  # if the gmt file has not already been downloaded
  if(!file.exists(dest_gmt_file)){
    # download the specified release from the URL
    download.file(
      paste(gmt_url,gmt_file,sep=""),
      destfile=dest_gmt_file
    )
  } else {
    dest_gmt_file <- gmt_files[1]
  }
}
# generate the command for the aggregate clinical subtype model
cmd <- paste("", gsea_jar,
             "GSEAPreRanked -gmx", dest_gmt_file,
             "-rnk" ,file.path(working_dir, ag_rnk_file), 
             "-collapse false -nperm 1000 -scoring_scheme weighted", 
             "-rpt_label ", analysis_name_ag,
             "  -plot_top_x 20 -rnd_seed 12345  -set_max 200",  
             " -set_min 15 -zip_report false ",
             " -out", output_dir, 
             " > gsea_output_ag.txt", sep=" ")
# if the output folder does not already exist
if (length(list.files(path=output_dir,
                      pattern="^clinical.GseaPreranked")) == 0) {
  system(cmd) # run the cmd
}

# and generate the command for the ER over-expression classifier model
cmd <- paste("", gsea_jar,
             "GSEAPreRanked -gmx", dest_gmt_file,
             "-rnk" ,file.path(working_dir, er_rnk_file), 
             "-collapse false -nperm 1000 -scoring_scheme weighted", 
             "-rpt_label ", analysis_name_er,
             "  -plot_top_x 20 -rnd_seed 12345  -set_max 200",  
             " -set_min 15 -zip_report false ",
             " -out", output_dir, 
             " > gsea_output_er.txt", sep=" ")
# if the output folder does not already exist
if (length(list.files(path=output_dir,
                      pattern="^ER.GseaPreranked")) == 0) {
  system(cmd) # run the cmd
}

2.1 What method did you use?

I chose to use GSEA’s PreRanked Analysis since I had familiarity with it through my journal entry and found it to be very informative on completion of the analysis. It was also flexible in terms of using whichever gene matrix transposed gene-set file I wanted, which meant I could redo the analysis programmatically if I needed to try again with a different or updated gene-set.

2.1.1 What gene-sets did you use? (Specify versions and cite your methods)

I chose to use the the Human gene-set from the BaderLab released on March 1st, 2025. The gene-sets were developed using the latest version of GO Human annotations on December 21, 2025, which means we are using the release dated most recently before this. As such, it includes

  • GO:BP : Gene Ontology: Biological Processes ; version 225 released 24 October, 2024

There is an option to include PFOCR, which is WikiPathways, however I did not include this since I performed the analysis only using GO:BP first and found it to be sufficient for my needs in terms of this analysis.

2.2 Summarize your enrichment results

There are a lot of individual plots available for specific terms.

First, the following plots agree with our volcano plots to give us more confidence in the remaining results.

Figure 5: Normalized Enrichment Score and Significance plots for both model designs. a, Aggregate model design, ie. across all clinical subtypes presented in this study; HER2+, HER2+/ER+, ER+, and TNBC. b, ER over-expression subtype classified by either over-expressed ER, or lack thereof. Produced by the GSEA PreRanked Analysis. Significance is determined via Benjamini-Hochberg correction for False Discovery Rate, p < 0.05.


I read in the resulting csv files from the GSEA reports.

ag_neg <- read.csv2(file.path(ag_dir, "gsea_report_for_na_neg_1743386287182.tsv"),
                        header=TRUE, sep="\t")
ag_pos <- read.csv2(file.path(ag_dir, "gsea_report_for_na_pos_1743386287182.tsv"),
                        header=TRUE, sep="\t")

er_neg <- read.csv2(file.path(er_dir, "gsea_report_for_na_neg_1743386532278.tsv"),
                        header=TRUE, sep="\t")
er_pos <- read.csv2(file.path(er_dir, "gsea_report_for_na_pos_1743386532278.tsv"),
                        header=TRUE, sep="\t")

I display the top hits for both models, both positively and negatively correlated.

Table 4: Negatively correlated top gene-set hits for aggregate model design across HER2+, HER2+/ER+, ER+, and TNBC.
x
17Q12 COPY NUMBER VARIATION SYNDROME%WIKIPATHWAYS_20250210%WP5287%HOMO SAPIENS
PHOSPHODIESTERASES IN NEURONAL FUNCTION%WIKIPATHWAYS_20250210%WP4222%HOMO SAPIENS
CELLULAR COMPONENT ASSEMBLY INVOLVED IN MORPHOGENESIS%GOBP%GO:0010927
REGULATION OF EXTRACELLULAR MATRIX ASSEMBLY%GOBP%GO:1901201
CELLULAR ANATOMICAL ENTITY MORPHOGENESIS%GOBP%GO:0032989
MYOTUBE DIFFERENTIATION%GOBP%GO:0014902
Table 5: Positively correlated top gene-set hits for aggregate model design across HER2+, HER2+/ER+, ER+, and TNBC.
x
MAJOR PATHWAY OF RRNA PROCESSING IN THE NUCLEOLUS AND CYTOSOL%REACTOME%R-HSA-6791226.5
INFLUENZA VIRAL RNA TRANSCRIPTION AND REPLICATION%REACTOME DATABASE ID RELEASE 91%168273
RRNA PROCESSING IN THE NUCLEUS AND CYTOSOL%REACTOME%R-HSA-8868773.5
PROTEIN SYNTHESIS: LEUCINE%SMPDB%SMP0111873
EUKARYOTIC TRANSLATION ELONGATION%REACTOME%R-HSA-156842.4
PROTEIN SYNTHESIS: LYSINE%SMPDB%SMP0111874
Table 6: Negatively correlated top gene-set hits for ER over-expression model design.
x
HALLMARK_INTERFERON_ALPHA_RESPONSE%MSIGDBHALLMARK%HALLMARK_INTERFERON_ALPHA_RESPONSE
HALLMARK_INTERFERON_GAMMA_RESPONSE%MSIGDBHALLMARK%HALLMARK_INTERFERON_GAMMA_RESPONSE
NUCLEAR DNA REPLICATION%GOBP%GO:0033260
B CELL MEDIATED IMMUNITY%GOBP%GO:0019724
IMMUNOGLOBULIN MEDIATED IMMUNE RESPONSE%GOBP%GO:0016064
ASSEMBLY OF COLLAGEN FIBRILS AND OTHER MULTIMERIC STRUCTURES%REACTOME%R-HSA-2022090.5
Table 7: Positively correlated top gene-set hits for ER over-expression model design.
x
REGULATION OF VASOCONSTRICTION%GOBP%GO:0019229
CELL-CELL ADHESION MEDIATED BY CADHERIN%GOBP%GO:0044331
PHYSIOLOGICAL AND PATHOLOGICAL HYPERTROPHY OF THE HEART%WIKIPATHWAYS_20250210%WP1528%HOMO SAPIENS
SMOOTH MUSCLE CONTRACTION%GOBP%GO:0006939
FATTY ACID DERIVATIVE BIOSYNTHETIC PROCESS%GOBP%GO:1901570
FOXO-MEDIATED TRANSCRIPTION OF OXIDATIVE STRESS, METABOLIC AND NEURONAL GENES%REACTOME DATABASE ID RELEASE 91%9615017

** Show some enrichment plots of interest! …

a, Aggregate model design, ie. across all clinical subtypes presented in this study; HER2+, HER2+/ER+, ER+, and TNBC. b, ER over-expression subtype classified by either over-expressed ER, or lack thereof. Produced by the GSEA PreRanked Analysis. Significance is determined via Benjamini-Hochberg correction for False Discovery Rate, p < 0.05.

http://localhost:8787/files/projects/GSE176078/gsea/clinical.GseaPreranked.1743386287182/enplot_MAJOR_PATHWAY_OF_RRNA_PROCESSING_IN_THE_NUCLEOLUS_AND_CYTOSOL_REACTOME_R-HSA-6791226.5_1.png

Figure 6: Some enrichment plots for both model designs. a, Aggregate model design, ie. across all clinical subtypes presented in this study; HER2+, HER2+/ER+, ER+, and TNBC. Presented is the enrichment plot for rRNA processing in the nucleus and cytosol reactome. b, ER over-expression subtype classified by either over-expressed ER, or lack thereof. Presented is the enrichment plot of cell-cell adhesion mediated cadherin binding. Produced by the GSEA PreRanked Analysis. Statistics and metrics are described on the GSEA website.


2.3 How do these results compare to the results from the thresholded analysis in Assignment 2? Compare qualitatively.

Interferons and cadherin-binding are familiar terms from assignment 2. Although the depth of detail we achieved was much less in assignment 2, and not only that, we had less scope due to the thresholds on our gene-sets. There are some similarities, and some differences, which is to be expected.

2.3.1 Is this a straight forward comparison? Why or Why not?

No, since the versions of data we are using is different. Also, the thresholded analysis does not contain as much information, and although we have gene-set size information available in our non-thresholded analysis results, it is not straight-forward.

3 Visualizing Gene-Set Enrichment Analysis in Cytoscape

Similarly to our analysis using GSEA, we will perform our analysis using Cytoscape via R code.

The code below is adapted from Ruth Isserlin [4].

We ensure to use the original gene-matrix transposed file so as not to hinder our analysis with the filtering present in the output .gmt from GSEA.

#use the non-filtered gmt
gmt_files <- list.files(path = output_dir, pattern = "\\.gmt")
# get the details on the files
details = file.info(file.path(output_dir,gmt_files))
# order from newest to oldest
details = details[with(details, order(as.POSIXct(mtime),decreasing = TRUE)), ]
#use the newest file:
gmt_gsea_file <- row.names(details)[1]
ag_edb <- file.path(ag_dir, "edb")
er_edb <- file.path(er_dir, "edb")

ag_res_edb <- file.path(ag_edb, "results.edb")
er_res_edb <- file.path(er_edb, "results.edb")

ag_ranks <- file.path(ag_edb, "ag_ranks.rnk")
er_ranks <- file.path(er_edb, "er_ranks.rnk")
# build the class file for aggregate design
ag_cls = "~/projects/GSE176078/ag.cls"
if (!file.exists(ag_cls)) {
  # num of samples of each class
  cat(as.character(subtype_counts[1:4,1]),sep = " ",file=ag_cls,append=TRUE)
  cat("\n", file=ag_cls, append=TRUE)
  # names of each class
  cat(c("#", "HER2+", "HER2+/ER+", "TNBC", "ER+"), sep = " ",file=ag_cls,append=TRUE)
  cat("\n", file=ag_cls, append=TRUE)
  # ordered name for each sample
  cat(types_df$subtype, sep = " ",file=ag_cls,append=TRUE)
  cat("\n", file=ag_cls, append=TRUE)
}

We must ensure cytoscape is running for the next sections of code. If everything is working properly, there will be a successful message from Cytoscape after we ping!

# define docker base url's
current_base = "host.docker.internal:1234/v1"
.defaultBaseUrl <- "http://host.docker.internal:1234/v1"

cytoscapePing(base.url = current_base)
You are connected to Cytoscape!

We are currently using Cytoscape version v1, 3.10.3.

# function to upload a local file to the host machine
to_cytoscape <- function(local_path) {
  bname <- basename(local_path)
  r <- POST(
    url = 
paste('http://host.docker.internal:1234/enrichmentmap/textfileupload?fileName=', 
                bname, sep=""),
    config = list(),
    body = list(file = upload_file(local_path)),
    encode = "multipart",
    handle = NULL
  )
  content(r,"parsed")$path
}
# starting with the aggregate design model, 
# upload local files and record the host path
ag_res_edb <- to_cytoscape(ag_res_edb)
ag_ranks <- to_cytoscape(ag_ranks)
gmt <- to_cytoscape(gmt_gsea_file)
ag_cls <- to_cytoscape(ag_cls)
# expr file ?

# and upload files for the ER over-expression model
er_res_edb <- to_cytoscape(er_res_edb)
er_ranks <- to_cytoscape(er_ranks)

3.1 Create an Enrichment map

pval <- 0.05
qval <- 0.05
sim <- 0.375
sim_metric <- "COMBINED" # or JACCARD

ag_network <- paste("aggregate", pval, qval, sep="_")

em_cmd = paste('enrichmentmap build analysisType="gsea" gmtFile=',
                gmt,
                'pvalue=', pval, 
                'qvalue=', qval,
                'similaritycutoff=', sim,
                'coefficients=', sim_metric,
                'ranksDataset1=', ag_ranks,
                'enrichmentsDataset1=', ag_res_edb, 
                'filterByExpressions=false',
                # 'expressionDataset1=',expression_file_fullpath,
                'classDataset1=', ag_cls,
                # 'gmtFile=', gmt,
                sep=" ")

# fetch the suid of the newly created network
ag_resp <- commandsGET(em_cmd, base.url = current_base)

# check if the cmd was successful or failed
if (grepl(pattern="Failed", ag_resp)) {
  paste(ag_resp)
} else {
  ag_suid <- ag_resp
}

curr_names <- getNetworkList(base.url = current_base)
if (ag_network %in% curr_names) {
  ag_network <- paste(ag_suid, ag_network, sep="_")
}

resp <- renameNetwork(title = ag_network,
                      network = as.numeric(ag_suid),
                      base.url = current_base)

And, for the ER over-expression model, I create another enrichment map.

pval <- 0.05
qval <- 0.05
sim <- 0.375
sim_metric <- "COMBINED" # or JACCARD

er_network <- paste("er", pval, qval, sep="_")

em_cmd = paste('enrichmentmap build analysisType="gsea" gmtFile=',
                gmt,
                'pvalue=', pval, 
                'qvalue=', qval,
                'similaritycutoff=', sim,
                'coefficients=', sim_metric,
                'ranksDataset1=', er_ranks,
                'enrichmentsDataset1=', er_res_edb, 
                'filterByExpressions=false',
                sep=" ")

# fetch the suid of the newly created network
er_resp <- commandsGET(em_cmd, base.url = current_base)

# check if the cmd was successful or failed
if (grepl(pattern="Failed", er_resp)) {
  paste(er_resp)
} else {
  er_suid <- er_resp
}

curr_names <- getNetworkList(base.url = current_base)
if (er_network %in% curr_names) {
  er_network <- paste(er_suid, er_network, sep="_")
}

er_resp <- renameNetwork(title = er_network,
                         network = as.numeric(er_suid),
                         base.url = current_base)

3.1.1 How many nodes and how many edges in the resulting map?

Our enrichment map network for the aggregate model design across all four clinical subtypes of breast cancer presented, HER2+/ER+, HER2+, ER+, and TNBC, has:

  • # nodes : 364
  • # edges : 2768

And the ER over-expression design across ER+/-, has:

  • # nodes : 82
  • # edges : 201

3.1.2 What thresholds were used to create this map? (make sure to record all thresholds)

I used the following thresholds for both networks:

  • p-value : 0.05
  • q-value : 0.05
  • similarity threshold : 0.375

I used the COMBINED similarity metric for these maps.

3.1.3 Include a screenshot of your network prior to manual layout.

Shown are the networks prior to manual layout. Note that this section could not be programmatically retrieved and displayed due to the limitations of using Cytoscape in R with Docker.

Both layouts are very messy before adjustment, and purely for demonstrative purposes.

Figure 7: Initial network layout for aggregate model design; HER2+, HER2+/ER+, ER+, and TNBC. Generated using Cytoscape via RCy3. p-value < 0.05, q-value < 0.05, similarity threshold < 0.375 with a combined similarity metric.
Figure 7: Initial network layout for aggregate model design; HER2+, HER2+/ER+, ER+, and TNBC. Generated using Cytoscape via RCy3. p-value < 0.05, q-value < 0.05, similarity threshold < 0.375 with a combined similarity metric.


Figure 8: Initial network layout for ER over-expression model; ER+/-. Generated using Cytoscape via RCy3. p-value < 0.05, q-value < 0.05, similarity threshold < 0.375 with a combined similarity metric.
Figure 8: Initial network layout for ER over-expression model; ER+/-. Generated using Cytoscape via RCy3. p-value < 0.05, q-value < 0.05, similarity threshold < 0.375 with a combined similarity metric.


3.2 Annotate your Network

Annotating the network is where the manual work begins and the figures start to look readable.

3.2.1 What parameters did you use to annotate the network? (make sure to list the default parameters you are using as well)

I added a class file in the GSEA format to add information about each sample’s classification according to the aggregate clinical subtype design, however I did not really see it present in the network.

I used the AutoAnnotate additional application to annotate using Gene-Set Descriptions. I selected the ‘Layout Network to avoid cluster overlap’ and adjusted some of the labels that were overlapping.

The nodes are colour-scaled by FDR q-value with darker-red nodes having values closer to 0.00, and lighter-red nodes having values closer to 0.05.

Cut-Off Values:

  • P-value: 0.05
  • FDR Q-value: 0.05
  • Jaccard Overlap Combined: 0.375
  • Test used: Jaccard Overlap Combined Index (k constant = 0.5)

Data Sets:

  • Dataset 1
  • Gene Sets File: …/em_fileupload_16120623913225671898/em_11162267974427327696_ Human_GOBP_AllPathways_noPFOCR_no_GO_iea_March_01_2025_symbol.gmt
  • Data Files: …/em_fileupload_16120623913225671898/em_6205993452311517617_results.edb
  • Ranks File: …/em_fileupload_16120623913225671898/em_13925529101006825111_ag_ranks.rnk
  • Positive Phenotype: UP
  • Negative Phenotype: DOWN

3.3 Make a publication-ready figure with proper legends.

The annotations present are already grouped and clearly highlighted. I added a legend to the top-left denoting the node colour-scaling. I selected the ‘Publication Ready’ option and it removed the labels of the individual nodes themselves, so the focus can be drawn to the annotations.

Figure 9: Annotated aggregate network layout; HER2+, HER2+/ER+, ER+, and TNBC. Generated using Cytoscape via RCy3, annotated using AutoAnnotate application in the Cytoscape interface. p-value < 0.05, q-value < 0.05, similarity threshold < 0.375 with a combined similarity metric.
Figure 9: Annotated aggregate network layout; HER2+, HER2+/ER+, ER+, and TNBC. Generated using Cytoscape via RCy3, annotated using AutoAnnotate application in the Cytoscape interface. p-value < 0.05, q-value < 0.05, similarity threshold < 0.375 with a combined similarity metric.


Figure 10: Annotated ER over-expression network layout; ER+/-. Generated using Cytoscape via RCy3, annotated using AutoAnnotate application in the Cytoscape interface. p-value < 0.05, q-value < 0.05, similarity threshold < 0.375 with a combined similarity metric.
Figure 10: Annotated ER over-expression network layout; ER+/-. Generated using Cytoscape via RCy3, annotated using AutoAnnotate application in the Cytoscape interface. p-value < 0.05, q-value < 0.05, similarity threshold < 0.375 with a combined similarity metric.


There is a major focus on the central grouping with some sparser nodes present on the outskirts of the network. I filtered nodes that did not have more than 5 connections, however they still showed up on the graph despite being highlighted differently in my initial network.

3.4 Collapse your network to a theme network.

For this section, I generated two themed networks for each of the model designs.

First, I generated a summary network to show a more concise and simple design highlighting the major connection points in this network.

Figure 11: Summary themed network for aggregate model design; HER2+, HER2+/ER+, ER+, and TNBC. Generated using Cytoscape via RCy3, cleaned using AutoAnnotate application in the Cytoscape interface to generate a Summary network. p-value < 0.05, q-value < 0.05, similarity threshold < 0.375 with a combined similarity metric.
Figure 11: Summary themed network for aggregate model design; HER2+, HER2+/ER+, ER+, and TNBC. Generated using Cytoscape via RCy3, cleaned using AutoAnnotate application in the Cytoscape interface to generate a Summary network. p-value < 0.05, q-value < 0.05, similarity threshold < 0.375 with a combined similarity metric.


Next, I generated a clustering at the most generic level for the aggregate design network.

Figure 12: Generic clustering network for aggregate model design; HER2+, HER2+/ER+, ER+, and TNBC. Generated using Cytoscape via RCy3, cleaned using AutoAnnotate application in the Cytoscape interface to generate the most generic clustering available. p-value < 0.05, q-value < 0.05, similarity threshold < 0.375 with a combined similarity metric.
Figure 12: Generic clustering network for aggregate model design; HER2+, HER2+/ER+, ER+, and TNBC. Generated using Cytoscape via RCy3, cleaned using AutoAnnotate application in the Cytoscape interface to generate the most generic clustering available. p-value < 0.05, q-value < 0.05, similarity threshold < 0.375 with a combined similarity metric.


Figure 13: Summary clustering network for ER over-expression model design; ER+/-. Generated using Cytoscape via RCy3, cleaned using AutoAnnotate application in the Cytoscape interface to generate a Summary network. p-value < 0.05, q-value < 0.05, similarity threshold < 0.375 with a combined similarity metric.
Figure 13: Summary clustering network for ER over-expression model design; ER+/-. Generated using Cytoscape via RCy3, cleaned using AutoAnnotate application in the Cytoscape interface to generate a Summary network. p-value < 0.05, q-value < 0.05, similarity threshold < 0.375 with a combined similarity metric.


Figure 14: Generic clustering network for ER over-expression model design; ER+/-. Generated using Cytoscape via RCy3, cleaned using AutoAnnotate application in the Cytoscape interface to generate the most generic clustering available. p-value < 0.05, q-value < 0.05, similarity threshold < 0.375 with a combined similarity metric.
Figure 14: Generic clustering network for ER over-expression model design; ER+/-. Generated using Cytoscape via RCy3, cleaned using AutoAnnotate application in the Cytoscape interface to generate the most generic clustering available. p-value < 0.05, q-value < 0.05, similarity threshold < 0.375 with a combined similarity metric.


3.4.1 What are the major themes present in this analysis?

Pretty clearly for the aggregate model design, the major theme is protein synthesis processes. The most generic level of grouping had no real effect on the nodes seemingly separate from the most central grouping, and so grouped the most related gene-sets into Protein Synthesis Processes.

This particular grouping majorly combines SRP Protein Synthesis, Nuclear Export Sumoylation, Process Purine Catabolism, and Strand DNA Templating, along with de novo folding, small subunit assembly, Tricistronic rRNA SSU, among a few others.

Apart from this major theme, the separate groups are fairly separate, although some possible mechanisms present themselves as interesting, such as the relation of Thymic IL2 1 Pathway and Spindle Checkpoint Chromosome to breast cancerous subtype differences.


For the ER over-expression model design, the major theme appears to be the Electron Transport Process, along with Phospholipid Phagocytosis and Strand Nuclear DNA.

Electron Transport Process groups Glycogenesis Type Deficiency, Process Diphosphate Metabolic, and Coupled Electron Transport.

3.4.2 Do they fit with the model?

It is not very informative to say that Protein Synthesis Processes fit as a determination in distinguishing different clinical subtypes of breast cancer. HER2 and ER over-expression or lack thereof classify these subtypes, and so it seems natural that protein synthesis is involved.

Similarly, the Electron Transport Process is hallmark to the entirety of cellular function. As to how it fits with ER over-expression or lack thereof in breast cancerous subtypes is unknown.

3.4.3 Are there any novel pathways or themes?

There are some novel pathways and themes, like that of Thymic IL2 1 Pathway and Spindle Checkpoint Chromosome which can be associated with possible mechanisms of breast cancer. As to how these separate the clinical subtypes of breast cancer is novel, but possible. Interleukin inflammation can contribute to environments conducive to cancerous growth and proliferation, similarly with problems in the cell cycle like that of spindle checkpoint(s).

Skin Epidermis Development seems quite far off from breast cancer. I am assuming metastases can be common for one reason or another, but it is very difficult to characterize this small grouping as being related to the clinical subtypes of our interest.

For the ER over-expression, it seems most of the pathways, even despite having only a few nodes, are rather relevant to the relative realm of breast cancerous pathology.

4 Interpretation

4.1 Do the enrichment results support conclusions or mechanisms discussed in the original paper?

The original paper included this enrichment analysis of their single-cell RNA sequencing samples. This Gene-Set Enrichment Analysis was performed using ClusterProfiler with gene-sets from the MSigDB HALLMARK collection. p-values < 0.05 were adjusted using Bonferroni.

Figure 15: Gene-Set Enrichment Analysis performed by the original publishers Wu. et al (2021)
Figure 15: Gene-Set Enrichment Analysis performed by the original publishers Wu. et al (2021)


My aggregate model design solely agrees with the findings of the publication on Mitotic Spindle. The remainder of my network does not agree with the findings whatsoever.

Similarly, my ER over-expression design lists Hallmark Interferon Response in agreement with the publication. Other than that, there is little agreement.

4.1.1 How do these results differ from the results you got in Assignment 2 thresholded methods?

In assignment 2, my enrichment results mentioned Interferons, and Cadherin-binding, but nothing else is too similar. Apart from the very generic conclusions being Protein Synthesis Processes and Electron Transport Processes.

4.2 Can you find evidence, ie. publications, to support some of the results that you see?

Not conclusively. Although there is always correlative evidence, especially in a field so researched as breast cancer, I do not believe the evidence is substantial enough to really say anything at this point. The network outcomes are too generic for any conclusions to be drawn from this.

4.2.1 How does the evidence support your result?

I struggled to find evidence to support these results since they are so generic.

5 Detailed View of Results

I chose to analyze the three significantly differentially expressed genes in the ER over-expression model: ANXA8, MKX, and CD207.

I found a network containing both ANXA8 and CD207 under the epidermis development GO biological process.

Figure 16: Network for epidermis development which includes both ANXA8 and CD207; two of the three significant genes in ER over-expression. Pulled by using the STITCH protein query on the respective genes of interest on Cytoscape.
Figure 16: Network for epidermis development which includes both ANXA8 and CD207; two of the three significant genes in ER over-expression. Pulled by using the STITCH protein query on the respective genes of interest on Cytoscape.

They interact through hsa-mir-205, which is a micro RNA. According to its associated gene card [5], it is associated with squamous cell carcinoma in the head and neck. This is an interesting association, and not far off from breast cancer, although a stretch for sure.

Looking further into squamous breast cancerous tissues brought me to this String network.

Figure 17: String Network for squamous carcinoma in breast tissue. Pulled by using the STITCH disease query on squamous carcinoma.
Figure 17: String Network for squamous carcinoma in breast tissue. Pulled by using the STITCH disease query on squamous carcinoma.

Notably, ERBB2 is present in yellow. This is the definition of expression of HER2, and so its relation to squamous carcinoma in breast cancerous tissue is very interesting. Additionally, we see BRCA1, a classic, and MUC1, which was in our aggregate model design.

6 Associated Journal Entry

My associated journal entry wiki link for this assignment is here.

7 Acknowledgments

This paper makes use of packages knitr [6], BiocManager [7], GEOquery [8], kableExtra [9], edgeR [10], limma [11], ComplexHeatmap [12], circlize [13], gprofiler2 [14], GSA [15], rcurl [16], ggplot2 [17], grid [18], gridExtra [19], png [20], RCy3 [21], & httr [22].

8 Bibliography

1. Wu SZ, Al-Eryani G, Roden DL, Junankar S, Harvey K, Andersson A, et al. A single-cell and spatially resolved atlas of human breast cancers. Nature genetics. 2021;53:1334–47.
2. Parker JS, Mullins M, Cheang MC, Leung S, Voduc D, Vickery T, et al. Supervised risk predictor of breast cancer based on intrinsic subtypes. Journal of clinical oncology. 2009;27:1160–7.
3. Isserlin R. Run GSEA from within r.
4. Isserlin R. Create enrichment map from r with GSEA results.
5. MalaCards. MIR205 gene - MicroRNA 205.
6. Xie Y. Dynamic documents with R and knitr. 2nd edition. Boca Raton, Florida: Chapman; Hall/CRC; 2015.
7. Morgan M, Ramos M. BiocManager: Access the bioconductor project package repository. 2024.
8. Davis S. GEOquery: Get data from NCBI gene expression omnibus (GEO). 2024.
9. Zhu H. kableExtra: Construct complex table with ’kable’ and pipe syntax. 2024.
10. Chen Y, Lun AT, McCarthy DJ, Chen L, Baldoni P, Ritchie ME, et al. edgeR: Empirical analysis of digital gene expression data in r. 2025.
11. Ritchie ME, Phipson B, Wu D, Hu Y, Law CW, Shi W, et al. limma powers differential expression analyses for RNA-sequencing and microarray studies. Nucleic Acids Research. 2015;43:e47.
12. Gu Z. Complex heatmap visualization. iMeta. 2022. https://doi.org/10.1002/imt2.43.
13. Gu Z, Gu L, Eils R, Schlesner M, Brors B. Circlize implements and enhances circular visualization in r. Bioinformatics. 2014;30:2811–2.
14. Kolberg L, Raudvere U, Kuzmin I, Vilo J, Peterson H. gprofiler2– an r package for gene list functional enrichment analysis and namespace conversion toolset g:profiler. F1000Research. 2020;9 (ELIXIR).
15. Efron B, Tibshirani R. GSA: Gene set analysis. 2024.
16. Temple Lang D. RCurl: General network (HTTP/FTP/...) client interface for r. 2024.
17. Wickham H, Chang W, Henry L, Pedersen TL, Takahashi K, Wilke C, et al. ggplot2: Create elegant data visualisations using the grammar of graphics. 2024.
18. R Core Team. R: A language and environment for statistical computing. Vienna, Austria: R Foundation for Statistical Computing; 2024.
19. Auguie B. gridExtra: Miscellaneous functions for "grid" graphics. 2017.
20. Urbanek S. Png: Read and write PNG images. 2022.
21. Gustavsen, A. J, Pai, Shraddha, Isserlin, Ruth, et al. RCy3: Network biology using cytoscape from within r. F1000Research. 2019. https://doi.org/10.12688/f1000research.20887.3.
22. Wickham H. Httr: Tools for working with URLs and HTTP. 2023.
LS0tCnRpdGxlOiAiQXNzaWdubWVudCAzIgpzdWJ0aXRsZTogIkRhdGEgU2V0IFBhdGh3YXkgYW5kIE5ldHdvcmsgQW5hbHlzaXMiCmF1dGhvcjogIkFubmFiZWxsYSBCcmVnYXp6aSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0aGVtZTogY29zbW8KICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBoaWRlCmJpYmxpb2dyYXBoeTogYTNfcmVmZXJlbmNlcy5iaWIKY3NsOiBiaW9tZWQtY2VudHJhbC5jc2wKbGluay1jaXRhdGlvbnM6IHRydWUKLS0tCgpgYGB7ciwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZXJyb3I9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQpsaWJyYXJ5KGtuaXRyKQppZiAoIXJlcXVpcmUoIkJpb2NNYW5hZ2VyIiwgcXVpZXRseSA9IFRSVUUpKQogICAgaW5zdGFsbC5wYWNrYWdlcygiQmlvY01hbmFnZXIiKQoKdHJ5Q2F0Y2goZXhwciA9IHsgbGlicmFyeSgiR0VPcXVlcnkiKX0sIAogICAgICAgICBlcnJvciA9IGZ1bmN0aW9uKGUpIHsgCiAgICAgICAgICAgaW5zdGFsbC5wYWNrYWdlcygiR0VPcXVlcnkiKX0sIAogICAgICAgICBmaW5hbGx5ID0gbGlicmFyeSgiR0VPcXVlcnkiKSkKdHJ5Q2F0Y2goZXhwciA9IHsgbGlicmFyeSgia2FibGVFeHRyYSIpfSwgCiAgICAgICAgIGVycm9yID0gZnVuY3Rpb24oZSkgeyAKICAgICAgICAgICBpbnN0YWxsLnBhY2thZ2VzKCJrYWJsZUV4dHJhIil9LCAKICAgICAgICAgZmluYWxseSA9IGxpYnJhcnkoImthYmxlRXh0cmEiKSkKdHJ5Q2F0Y2goZXhwciA9IHsgbGlicmFyeSgiZWRnZVIiKX0sIAogICAgICAgICBlcnJvciA9IGZ1bmN0aW9uKGUpIHsgCiAgICAgICAgICAgaW5zdGFsbC5wYWNrYWdlcygiZWRnZVIiKX0sIAogICAgICAgICBmaW5hbGx5ID0gbGlicmFyeSgiZWRnZVIiKSkKdHJ5Q2F0Y2goZXhwciA9IHsgbGlicmFyeSgibGltbWEiKX0sIAogICAgICAgICBlcnJvciA9IGZ1bmN0aW9uKGUpIHsgCiAgICAgICAgICAgaW5zdGFsbC5wYWNrYWdlcygibGltbWEiKX0sIAogICAgICAgICBmaW5hbGx5ID0gbGlicmFyeSgibGltbWEiKSkKaWYgKCFyZXF1aXJlKCJDb21wbGV4SGVhdG1hcCIsIHF1aWV0bHkgPSBUUlVFKSkKICAgIEJpb2NNYW5hZ2VyOjppbnN0YWxsKCJDb21wbGV4SGVhdG1hcCIpCmlmICghcmVxdWlyZSgiY2lyY2xpemUiLCBxdWlldGx5ID0gVFJVRSkpCiAgICBCaW9jTWFuYWdlcjo6aW5zdGFsbCgiY2lyY2xpemUiKQp0cnlDYXRjaChleHByID0geyBsaWJyYXJ5KCJncHJvZmlsZXIyIil9LCAKICAgICAgICAgZXJyb3IgPSBmdW5jdGlvbihlKSB7IAogICAgICAgICAgIGluc3RhbGwucGFja2FnZXMoImdwcm9maWxlcjIiKX0sIAogICAgICAgICBmaW5hbGx5ID0gbGlicmFyeSgiZ3Byb2ZpbGVyMiIpKQp0cnlDYXRjaChleHByID0geyBsaWJyYXJ5KCJHU0EiKX0sIAogICAgICAgICBlcnJvciA9IGZ1bmN0aW9uKGUpIHsgCiAgICAgICAgICAgaW5zdGFsbC5wYWNrYWdlcygiR1NBIil9LCAKICAgICAgICAgZmluYWxseSA9IGxpYnJhcnkoIkdTQSIpKQp0cnlDYXRjaChleHByID0geyBsaWJyYXJ5KCJnZ3Bsb3QyIil9LCAKICAgICAgICAgZXJyb3IgPSBmdW5jdGlvbihlKSB7IAogICAgICAgICAgIGluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKX0sIAogICAgICAgICBmaW5hbGx5ID0gbGlicmFyeSgiZ2dwbG90MiIpKQp0cnlDYXRjaChleHByID0geyBsaWJyYXJ5KCJSQ3VybCIpIH0sCiAgICAgICAgIGVycm9yID0gZnVuY3Rpb24oZSkgewogICAgICAgICAgIGluc3RhbGwucGFja2FnZXMoIlJDdXJsIil9LAogICAgICAgICBmaW5hbGx5ID0gbGlicmFyeSgiUkN1cmwiKSkKCnRyeUNhdGNoKGV4cHIgPSB7IGxpYnJhcnkoIlJDeTMiKX0sIAogICAgICAgICBlcnJvciA9IGZ1bmN0aW9uKGUpIHsgCiAgICAgICAgICAgQmlvY01hbmFnZXI6Omluc3RhbGwoIlJDeTMiKX0sIAogICAgICAgICBmaW5hbGx5ID0gbGlicmFyeSgiUkN5MyIpKQp0cnlDYXRjaChleHByID0geyBsaWJyYXJ5KCJodHRyIil9LCAKICAgICAgICAgZXJyb3IgPSBmdW5jdGlvbihlKSB7IAogICAgICAgICAgIEJpb2NNYW5hZ2VyOjppbnN0YWxsKCJodHRyIil9LCAKICAgICAgICAgZmluYWxseSA9IGxpYnJhcnkoImh0dHIiKSkKCmxpYnJhcnkoZ3JpZCkKbGlicmFyeShwbmcpCmxpYnJhcnkoZ3JpZEV4dHJhKQoKb3B0aW9ucyhrbml0ci50YWJsZS5mb3JtYXQgPSAiaHRtbCIpCmBgYAoKIyBJbnRyb2R1Y3Rpb24KCkJ1bGsgUk5BIHNlcXVlbmNpbmcgZGF0YSBvbiAyNCBwcmUtdHJlYXRtZW50IGJyZWFzdCBjYW5jZXIgdHVtb3VycyBwZXJmb3JtZWQgYnkgV3UgZXQgYWwuIFtAd3UyMDIxc2luZ2xlXSB3YXMgZG93bmxvYWRlZCBmcm9tIGBHRU9gIHdpdGggYWNjZXNzaW9uIFtHU0UxNzYwNzhdKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvZ2VvL3F1ZXJ5L2FjYy5jZ2k/YWNjPUdTRTE3NjA3OCksIGFuZCBbYXNzb2NpYXRlZCBwdWJsaWNhdGlvbl0oaHR0cHM6Ly9wbWMubmNiaS5ubG0ubmloLmdvdi9hcnRpY2xlcy9QTUM5MDQ0ODIzLykuCgpgYGB7cn0KZ2VvX2lkIDwtICJHU0UxNzYwNzgiCmBgYAoKYGBge3IsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KZ3NlIDwtIGdldEdFTyhnZW9faWQsIEdTRU1hdHJpeD1GQUxTRSkKZ3BsIDwtIG5hbWVzKGdzZUBncGxzKQpncGxfaW5mbyA8LSBNZXRhKGdldEdFTyhncGwpKQpgYGAKClRoaXMgZGF0YXNldCB3YXMgc2VxdWVuY2VkIHVzaW5nIGByIGdwbF9pbmZvJHRpdGxlYCwgc3VibWl0dGVkIG9uIGByIGdwbF9pbmZvJHN1Ym1pc3Npb25fZGF0ZWAuCgpCcmVhc3QgY2FuY2VycyBhcmUgY2xpbmljYWxseSBzdHJhdGlmaWVkIGJhc2VkIG9uOgoKLSBleHByZXNzaW9uIG9mIHRoZSBlc3Ryb2dlbiByZWNlcHRvciAoKkVSKiksIAotIGV4cHJlc3Npb24gb2YgdGhlIHByb2dlc3Rlcm9uZSByZWNlcHRvciAoKlBSKiksIGFuZAotIG92ZXJleHByZXNzaW9uIG9mICpIRVIyKiAob3IgYW1wbGlmaWNhdGlvbiBvZiAqSEVSMiogZ2VuZSAqRVJCQjIqKQoKVGhpcyByZXN1bHRzIGluIHRoZSBmb2xsb3dpbmcgdGhyZWUgX19jbGluaWNhbCBzdWJ0eXBlc19fIHdpdGhpbiB0aGlzIGRhdGFzZXQ6CgotIEx1bWluYWwgaWUuIEVSKzsgKCpFUisqLCAqUFIrLy0qKQotIEhFUjIrOyAoKkhFUjIrKiwgKkVSKy8tKiwgKlBSKy8tKikKLSBUcmlwbGUgTmVnYXRpdmUgaWUuIFROQkM7ICgqRVItKiwgKlBSLSosICpIRVIyLSopCgpCcmVhc3QgY2FuY2VycyBhcmUgYWxzbyBzdHJhdGlmaWVkIG9uIGJ1bGsgdHJhbnNjcmlwdG9taWMgcHJvZmlsaW5nIHZpYSBQQU01MCBnZW5lIHNpZ25hdHVyZXMgW0BwYXJrZXIyMDA5c3VwZXJ2aXNlZF0gZGVzY3JpYmluZyBmaXZlIF9fbW9sZWN1bGFyIHN1YnR5cGVzX186IEx1bWluYWwgQSwgTHVtaW5hbCBCLCBIRVIyLWVucmljaGVkLCBCYXNhbC1saWtlLCBhbmQgTm9ybWFsLWxpa2UuCgpUaGUgfjcwLTgwJSBjb25jb3JkYW5jZSBiZXR3ZWVuIGNsaW5pY2FsIGFuZCBtb2xlY3VsYXIgc3VidHlwZXMgbW90aXZhdGVkIHRoaXMgc3R1ZHkgdG8gaW1wcm92ZSBmdW5jdGlvbmFsIHVuZGVyc3RhbmRpbmcgb2YgYnJlYXN0IGNhbmNlciBpbiBhIGJyb2FkZXIgYW5kIG1vcmUgY29oZXJlbnQgc2Vuc2UuCgpGb3IgdGhpcyBzdHVkeSwgdGhlIGNsaW5pY2FsIHN1YnR5cGUgY29uZGl0aW9ucyBjbGFzc2lmaWVkIGFyZSBhcyBmb2xsb3dzOgoKLSBgSEVSMitgIDsgKCpIRVIyKyosICpFUi0qLCAqUFIrLy0qKQotIGBIRVIyKy9FUitgIDsgKCpIRVIyKyosICpFUisqLCAqUFIrLy0qKQotIGBFUitgIDsgKCpIRVIyLSosICpFUisqLCAqUFIrLy0qKQotIGBUTkJDYCA7ICgqSEVSMi0qLCAqRVItKiwgKlBSLSopCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgZWNobz1GQUxTRX0Kbm9ybWFsaXplZF9jb3VudHMgPC0gcmVhZC50YWJsZSgKICBmaWxlPWZpbGUucGF0aChnZXR3ZCgpLCBnZW9faWQsCiAgICAgICAgICAgICAgICAgcGFzdGUoZ2VvX2lkLCAKICAgICAgICAgICAgICAgICAgICAgICAibm9ybWFsaXplZF9jb3VudHMudHh0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgc2VwPSJfIikpLAogIGhlYWRlcj1UUlVFLCBzZXA9Ilx0IiwgCiAgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSwgCiAgY2hlY2submFtZXM9RkFMU0UpCmBgYAoKVGhlIGRpc3RyaWJ1dGlvbiBvZiBjbGluaWNhbCBzdWJ0eXBlcyBhY3Jvc3MgdGhlIDI0IHNhbXBsZXMgaXMgc2hvd24gaW4gdGFibGUgMS4KCmBgYHtyLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBlcnJvcj1GQUxTRSwgcmVzdWx0cz0naGlkZSd9CnR5cGVzIDwtIGRvLmNhbGwocmJpbmQsCiAgICAgICAgICAgICAgICAgbGFwcGx5KGdzZUBnc21zLCwKICAgICAgICAgICAgICAgICAgICAgICAgRlVOPWZ1bmN0aW9uKHgsIC4uLil7CiAgICAgICAgICAgICAgICAgICAgICAgICAgYyh4QGhlYWRlciR0aXRsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhAaGVhZGVyJGNoYXJhY3RlcmlzdGljc19jaDEpfSkpWyxjKDEsMildCnR5cGVzWywyXSA8LSBnc3ViKHR5cGVzWywyXSwKICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICJjbGluaWNhbF9zdWJ0eXBlOiAiLAogICAgICAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICIiKQoKcHJlc2VudCA8LSBjb2xuYW1lcyhub3JtYWxpemVkX2NvdW50cykKdHlwZXMgPC0gdHlwZXNbd2hpY2godHlwZXNbLDFdICVpbiUgcHJlc2VudCksXQoKdHlwZXMgPC0gY2JpbmQodHlwZXMsIGdyZXBsKCJeW0hdW0VdW1JdWzJdWytdIiwgdHlwZXNbLDJdKSkKdHlwZXMgPC0gY2JpbmQodHlwZXMsIGdyZXBsKCJbRV1bUl1bK10kIiwgdHlwZXNbLDJdKSkKY29sbmFtZXModHlwZXMpIDwtIGMoInNhbXBsZSIsICJzdWJ0eXBlIiwgImhlcjIiLCAiZXIiKQp0eXBlc19kZiA8LSBhcy5kYXRhLmZyYW1lKHR5cGVzKQpgYGAKCmBgYHtyLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBlcnJvcj1GQUxTRSwgcmVzdWx0cz0naGlkZSd9CmhlcjIgPSBsZW5ndGgod2hpY2godHlwZXNbLCJzdWJ0eXBlIl0gPT0gIkhFUjIrIikpCmhlcjJlciA9IGxlbmd0aCh3aGljaCh0eXBlc1ssInN1YnR5cGUiXSA9PSAiSEVSMisvRVIrIikpCnRuYmMgPSBsZW5ndGgod2hpY2godHlwZXNbLCJzdWJ0eXBlIl0gPT0gIlROQkMiKSkKZXIgPSBsZW5ndGgod2hpY2godHlwZXNbLCJzdWJ0eXBlIl0gPT0gIkVSKyIpKQp0b3RhbCA9IHN1bShoZXIyLCBoZXIyZXIsIHRuYmMsIGVyKQoKc3VidHlwZV9jb3VudHMgPSBkYXRhLmZyYW1lKGMoaGVyMiwgaGVyMmVyLCB0bmJjLCBlciwgdG90YWwpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID0gYygiSEVSMisiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkhFUjIrL0VSKyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVE5CQyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRVIrIiwgIlRvdGFsIikpCnN1YnR5cGVfY291bnRzJHBlcmNlbnRhZ2VzID0gc3VidHlwZV9jb3VudHNbLDFdICogMTAwIC8gdG90YWwKYGBgCgpgYGB7ciwgZWNobz1GQUxTRSwgcmVzdWx0cz0nYXNpcyd9CnN1YnR5cGVfY291bnRzICU+JQogIGtuaXRyOjprYWJsZShjYXB0aW9uPSJUYWJsZSAxOiBDbGluaWNhbCBicmVhc3QgY2FuY2VyIHN1YnR5cGUgc3BsaXRzIGluIG91ciBkYXRhc2V0IiwgCiAgICAgIGRpZ2l0cz0yLAogICAgICBjb2wubmFtZXM9YygiQ291bnQiLCAiUGVyY2VudCIpKSAlPiUKICBrYWJsZV9zdHlsaW5nKCkgJT4lCiAgcm93X3NwZWMoNSwgYm9sZCA9IFQpCmBgYAoKVGhpcyBsZWFkcyB0byAKCiogYHIgNDAwLzI0YCUgb2Ygc2FtcGxlcyBjb250YWluaW5nIGBIRVIyYCBleHByZXNzaW9uLCBhbmQgCiogYHIgMTQwMC8yNGAlIG9mIHNhbXBsZXMgY29udGFpbmluZyBgRVJgIGV4cHJlc3Npb24sIAoKV2l0aCB0aGUgb3ZlcmxhcHMgZ2l2aW5nIHVzIAoKKiBgciAyMDAvNGAlIG9mIHRob3NlIHdpdGggYEhFUjJgIGV4cHJlc3NlZCBhbHNvIGhhZCBgRVJgIGV4cHJlc3NlZCwgCiogYHIgMjAwLzE0YCUgb2YgdGhvc2Ugd2l0aCBgRVJgIGV4cHJlc3NlZCBhbHNvIGhhZCBgSEVSMmAgZXhwcmVzc2VkLgoKClRoZSByYXcgY291bnRzIHdlcmUgY2xlYW5lZCwgbWFwcGVkIHRvIFtIVUdPIEdlbmUgTm9tZW5jbGF0dXJlIENvbW1pdHRlZSAoSEdOQykgU3ltYm9sc10oaHR0cHM6Ly93d3cuZ2VuZW5hbWVzLm9yZy8pLCBhbmQgbm9ybWFsaXplZCB0byBwcm9kdWNlIGZpbmFsIGNvdW50cy4gT2YgdGhlIG9yaWdpbmFsIGA1ODM4N2AgZ2VuZXMsIHdlIHdlcmUgYWJsZSB0byBtYXAgYW5kIHByb2R1Y2UgYDI4NzEyYCB1bnZlcnNpb25lZCwgdW5pcXVlIGdlbmVzLCBvZiB3aGljaCBmaWx0ZXJpbmcgb3V0bGllcnMgKGtlZXBpbmcgZ2VuZXMgcHJlc2VudCBpbiBhIG1pbmltdW0gb2YgYDEyYCBzYW1wbGVzKSByZXN1bHRlZCBpbiBgMTQ4MDBgIGdlbmVzIHJlbWFpbmluZy4gCgpUaGUgZGVuc2l0eSBwbG90IHNob3dzIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIGNsZWFuZWQsIGZpbHRlcmVkLCBhbmQgbm9ybWFsaXplZCBjb3VudHMgcGVyIG1pbGxpb24gYWNyb3NzIGFsbCBzYW1wbGVzICh2YXJ5aW5nIGNvbG91cnMpLiAKCjxici8+CgohW0ZpZ3VyZSAxOiBTbW9vdGhpbmcgZGVuc2l0eSBvZiBmaWx0ZXJlZCBhbmQgbm9ybWFsaXplZCBDUE0gY291bnRzIGZvciAyNCBzYW1wbGVzIGFjcm9zcyBmb3VyIGNsaW5pY2FsIHN1YnR5cGVzIG9mIGJyZWFzdCBjYW5jZXIgdGlzc3VlLiBDb3VudHMgd2VyZSBmaWx0ZXJlZCB3aXRoIGBlZGdlUmAncyBgY3BtKClgIHRocmVzaG9sZGVkIGF0IGEgbWluaW11bSBzdW0gb2YgMTIgQ1BNIGFjcm9zcyBzYW1wbGVzIGZvciBlYWNoIGdlbmUuIENvdW50cyB3ZXJlIG5vcm1hbGl6ZWQgd2l0aCBgZWRnZVJgJ3MgYERHRUxpc3QoKWAgYWNyb3NzIGFsbCBmb3VyIGNsaW5pY2FsIHN1YnR5cGVzLiBOb3JtYWxpemF0aW9uIGZhY3RvcnMgd2VyZSBjYWxjdWxhdGVkIHZpYSBUTU0uIF0oL2hvbWUvcnN0dWRpby9wcm9qZWN0cy9maWd1cmVzL0dTRTE3NjA3OF9maWx0X25vcm1fZGVuc2l0eS5wbmcpCgoKPGJyLz4KRGlzcGVyc2lvbiB3YXMgY2FsY3VsYXRlZCB1c2luZyBgZWRnZVJgIHRvIGRlc2NyaWJlIGRldmlhdGlvbiBvZiB2YXJpYW5jZSBmcm9tIHRoZSBtZWFuLiBUaGUgQmlvbG9naWNhbCBDb2VmZmljaWVudCBvZiBWYXJpYXRpb24gKEJDVikgaXMgZGlzcGVyc2lvbi1zcXVhcmVkLCBhbmQgcmVwcmVzZW50cyB0aGUgbWVhbi12YXJpYW5jZSByZWxhdGlvbnNoaXAgYW1vbmcgZ2VuZXMuCgohW0ZpZ3VyZSAyOiBCaW9sb2dpY2FsIENvZWZmaWNpZW50IG9mIFZhcmlhdGlvbiAoRGlzcGVyc2lvbiBzcXVhcmVkKSBmb3IgMjQgc2FtcGxlcyBhY3Jvc3MgZm91ciBjbGluaWNhbCBzdWJ0eXBlcyBvZiBicmVhc3QgY2FuY2VyIHRpc3N1ZSBnZW5lLXdpc2UuIERpc3BlcnNpb24gd2FzIGNhbGN1bGF0ZWQgdXNpbmcgYGVkZ2VSYCdzIGBwbG90QkNWKClgIG9uIHRoZSBtb2RlbCBkZXNpZ25lZCBhY3Jvc3MgYWxsIGZvdXIgY2xpbmljYWwgc3VidHlwZXMuXSgvaG9tZS9yc3R1ZGlvL3Byb2plY3RzL2ZpZ3VyZXMvR1NFMTc2MDc4X2Jjdi5wbmcpCgo8YnIvPgpUaGUgbm9ybWFsaXplZCBjb3VudHMgd2VyZSBtb2RlbGVkIGJ5IHR3byBkZXNpZ25zLiBUaGUgZmlyc3QgYmVpbmcgYW4gYWdncmVnYXRlIGRlc2lnbiBjb25zaWRlcmluZyBhbGwgY2xpbmljYWwgc3VidHlwZXMgYXMgZGlzdGluY3QsIGllLiAqSEVSMisvRVIrKiwgKkhFUjIrKiwgKkVSKyosIGFuZCAqVE5CQyouIFRoZSBzZWNvbmQgYmVpbmcgYSBzcGxpdCBiaW5hcnktcGFpcmluZyBtb2RlbCBjb21iaW5pbmcgdGhlIHR3byBzZXBhcmF0ZSBjbGFzc2lmaWNhdGlvbiBzdWJ0eXBlcywgaWUuICpIRVIyKy8tKiBhbmQgKkVSKy8tKiBhcyBhIGJpbmFyeSBwYWlyLiBUaGUgc2VwYXJhdGUgbW9kZWwgZGVzaWducyByZXByZXNlbnRlZCBkaWZmZXJlbnQgcGVyc3BlY3RpdmVzIG9uIGxhYmVsaW5nIHRoZSBkYXRhIGFuZCBhbGxvdyBmb3IgbW9yZSBzcGVjaWZpYyBvciBnZW5lcmljIGNvbmNsdXNpb25zLgoKYGBge3J9CiMgYWdncmVnYXRlIG1vZGVsIGRlc2lnbgptb2RlbF9kZXNpZ24gPC0gbW9kZWwubWF0cml4KH4gdHlwZXNfZGYkc3VidHlwZSkKCiMgc3BsaXQgbW9kZWwgZGVzaWduIChiaW5hcnkgcGFpcnMpCnNwbHRfbW9kZWxfZGVzaWduIDwtIG1vZGVsLm1hdHJpeCh+IHR5cGVzX2RmJGhlcjIgKyB0eXBlc19kZiRlcikKYGBgCgpUaGUgYFF1YXNpLUxpa2VsaWhvb2QgTW9kZWxgIGZyb20gYGVkZ2VSYCB3YXMgdXNlZCB0byBwcm9kdWNlIGBRdWFzaS1MaWtlbGlob29kIEZpdHNgIGZvciBlYWNoIG1vZGVsIGRlc2lnbiwgYXQgd2hpY2ggcG9pbnQgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gd2FzIGNhbGN1bGF0ZWQgYWNyb3NzIHRoZSBtb2RlbHMuCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgZWNobz1GQUxTRSwgcmVzdWx0cz0naGlkZSd9Cm5vcm1fbWF0cml4IDwtIGFzLm1hdHJpeChub3JtYWxpemVkX2NvdW50cykKYGBgCgpgYGB7cn0KIyBub3JtYWxpemVkIGNvdW50cyBncm91cGVkIGJ5IGNsaW5pY2FsIHN1YnR5cGUKZCA8LSBER0VMaXN0KGNvdW50cz1ub3JtX21hdHJpeCwgCiAgICAgICAgICAgICBncm91cD10eXBlc19kZiRzdWJ0eXBlKQoKIyBlc3RpbWF0ZSBkaXNwZXJzaW9uIG9uIHN1YnR5cGUgbW9kZWwgZGVzaWduCmRfIDwtIGVzdGltYXRlRGlzcChkLCBtb2RlbF9kZXNpZ24pCnFsZml0IDwtIGdsbVFMRml0KGRfLCBtb2RlbF9kZXNpZ24pCgojIGluIHBhcmFsbGVsLCBlc3RpbWF0ZSBkaXNwZXJzaW9uIG9uIGJpbmFyeSBwYWlyaW5nIG1vZGVsIGRlc2lnbgpkX3NwbHQgPC0gZXN0aW1hdGVEaXNwKGQsIHNwbHRfbW9kZWxfZGVzaWduKQpxbGZpdF9zcGx0IDwtIGdsbVFMRml0KGRfc3BsdCwgc3BsdF9tb2RlbF9kZXNpZ24pCgojIGZpdCBzdWJ0eXBlIG1vZGVsIGRlc2lnbgpxbGYuc3VidHlwZXMgPC0gZ2xtUUxGVGVzdChxbGZpdCkKCiMgZml0IHNwbGl0IG1vZGVsIGRlc2lnbgpxbGYuaGVyMnAgPC0gZ2xtUUxGVGVzdChxbGZpdF9zcGx0LCAKICAgICAgICAgICAgICAgICAgICAgICAgY29lZj0ndHlwZXNfZGYkZXJUUlVFJykKcWxmLmVycCA8LSBnbG1RTEZUZXN0KHFsZml0X3NwbHQsIAogICAgICAgICAgICAgICAgICAgICAgY29lZj0ndHlwZXNfZGYkaGVyMlRSVUUnKQpgYGAKClRoZSBfX0JlbmphbWluaS1Ib2NoYmVyZ19fIG1ldGhvZCBmb3IgZmFsc2UgZGlzY292ZXJ5IHdhcyB1c2VkIHRvIGNvcnJlY3QgcC12YWx1ZXMgdG8gY2xhc3NpZnkgdGhlIHJlc3VsdGluZyBnZW5lcyB0aGF0IHBhc3NlZCBjb3JyZWN0aW9uIGZvciBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBpbiB0aGVpciByZXNwZWN0aXZlIG1vZGVscywgcHJvZHVjaW5nIHRoZSBmb2xsb3dpbmcgdm9sY2FubyBwbG90cy4gTm90ZSB0aGF0IG9ubHkgdGhlIGFnZ3JlZ2F0ZSBkZXNpZ24gYW5kICpFUiogc3BlY2lmaWMgZXhwcmVzc2lvbiBtb2RlbHMgYXJlIHNob3duIHNpbmNlIG5vIGdlbmVzIHBhc3NlZCBjb3JyZWN0aW9uIGZvciB0aGUgKkhFUjIqIHNwZWNpZmljIGRlc2lnbi4KPGJyLz4KCiFbRmlndXJlIDM6IFZvbGNhbm8gUGxvdCBmb3Igc2lnbmlmaWNhbnRseSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMgaW4gMjQgc2FtcGxlcyBhY3Jvc3MgZm91ciBjbGluaWNhbCBzdWJ0eXBlcyBvZiBicmVhc3QgY2FuY2VyIHRpc3N1ZSAoYWdncmVnYXRlIGRlc2lnbikuIERpZmZlcmVudGlhbCBleHByZXNzaW9uIHdhcyBjYWxjdWxhdGVkIGFjcm9zcyB0aGUgYWdncmVnYXRlIG1vZGVsIGRlc2lnbiBhY3Jvc3MgYWxsIGZvdXIgY2xpbmljYWwgc3VidHlwZXMuIFNpZ25pZmljYW50IGJlZm9yZSBjb3JyZWN0aW9uIGlzIHJlcHJlc2VudGVkIGJ5IHAgPCAwLjA1LCB3aXRoIHNpZ25pZmljYW50IGFmdGVyIGNvcnJlY3Rpb24gYmVpbmcgRkRSIDwgMC4wNS5dKC9ob21lL3JzdHVkaW8vcHJvamVjdHMvZmlndXJlcy92b2xjYW5vX2FnZ3JlZ2F0ZS5wbmcpCgo8YnIvPgoKVGhlIGFnZ3JlZ2F0ZSBtb2RlbCBoaWdobGlnaHRzIGluIHJlZCAqQ0QyMDcqLCAqTUtYKiwgYW5kICpBTlhBOCogYXMgZ2VuZXMgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgYWZ0ZXIgY29ycmVjdGlvbiBmb3IgZmFsc2UgZGlzY292ZXJ5LgoKIVtGaWd1cmUgNDogVm9sY2FubyBQbG90IGZvciBzaWduaWZpY2FudGx5IGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyBpbiAyNCBzYW1wbGVzIGFjcm9zcyBiaW5hcnkgb3Zlci1leHByZXNzaW9uIG9mIEVSIGNsaW5pY2FsIHN1YnR5cGVzIG9mIGJyZWFzdCBjYW5jZXIgdGlzc3VlIChzcGxpdCBkZXNpZ24pLiBEaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiB3YXMgY2FsY3VsYXRlZCBhY3Jvc3MgRVIgZXhwcmVzc2lvbiBkZXNpZ24uIFNpZ25pZmljYW50IGJlZm9yZSBjb3JyZWN0aW9uIGlzIHJlcHJlc2VudGVkIGJ5IHAgPCAwLjA1LCB3aXRoIHNpZ25pZmljYW50IGFmdGVyIGNvcnJlY3Rpb24gYmVpbmcgRkRSIDwgMC4wNS5dKC9ob21lL3JzdHVkaW8vcHJvamVjdHMvZmlndXJlcy92b2xjYW5vX2VyLnBuZykKCjxici8+CgpUaGUgc3BsaXQgbW9kZWwgaW4gdGVybXMgb2YgKkVSKiBvdmVyLWV4cHJlc3Npb24gaGlnaGxpZ2h0cyBpbiByZWQgKkVQSEEzKiwgKktDTk1CMiosICpDTEVDMUIqLCAqQ1lQMkcxUCosICpDREgyNiosICpDQVNDMyosICpURkYzKiwgKlJBUEdFRkwxKiwgKk1TTDEqLCAqTVVDNCosIGFuZCAqVEhSQSogYXMgZ2VuZXMgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgYWZ0ZXIgY29ycmVjdGlvbiBmb3IgZmFsc2UgZGlzY292ZXJ5LgoKVXNpbmcgdGhlc2UgbW9kZWxzLCBub24tdGhyZXNob2xkZWQgZ2VuZS1zZXRzIGNhbiBiZSBwdWxsZWQgYnkgcmFua2luZyBhY2NvcmRpbmcgdG8gLWxvZyhwLXZhbHVlcykgYW5kIHNpZ25pbmcgYWNjb3JkaW5nIHRvIHRoZSBsb2cgZm9sZC1jaGFuZ2UuCgpgYGB7cn0KIyBjcmVhdGUgbm9uLXRocmVzaG9sZGVkIGdlbmUgc2V0cwoKIyBhY3Jvc3MgYWxsIGNsaW5pY2FsIHN1YnR5cGVzCm50X2dlbmVzZXQgPC0gcWxmLnN1YnR5cGVzJHRhYmxlCm50X2dlbmVzZXRbLCJSYW5rIl0gPC0gLWxvZzEwKG50X2dlbmVzZXQkUFZhbHVlKSAqIHNpZ24obnRfZ2VuZXNldCRsb2dGQykKbnRfZ2VuZXNldCA8LSBudF9nZW5lc2V0W29yZGVyKG50X2dlbmVzZXQkUmFuaywgZGVjcmVhc2luZz1UUlVFKSxdCgojIGFjcm9zcyBFUiBvdmVyLWV4cHJlc3Npb24KZXJfZ2VuZXNldCA8LSBxbGYuZXJwJHRhYmxlCmVyX2dlbmVzZXRbLCJSYW5rIl0gPC0gLWxvZzEwKGVyX2dlbmVzZXQkUFZhbHVlKSAqIHNpZ24oZXJfZ2VuZXNldCRsb2dGQykKZXJfZ2VuZXNldCA8LSBlcl9nZW5lc2V0W29yZGVyKGVyX2dlbmVzZXQkUmFuaywgZGVjcmVhc2luZz1UUlVFKSxdCmBgYAoKVGhlIHJhbmtlZCBnZW5lLXNldHMgYXJlIHNhdmVkIGFzIGAucm5rYCBmaWxlcyBmb3IgZnVydGhlciBhbmFseXNpcyBpbiB0aGUgcmVtYWluZGVyIG9mIHRoaXMgcmVwb3J0LgoKYGBge3J9CiMgZm9yIHRoZSBhZ2dyZWdhdGUgY2xpbmljYWwgc3VidHlwZSBtb2RlbAojIGNyZWF0ZSBhIHNlcGFyYXRlIHJhbmtzIG1hdHJpeCB3aXRoIG9ubHkgZ2VuZSBuYW1lIGFuZCByYW5rCmdlbmVzZXRfcmFua3MgPC0gY2JpbmQocm93bmFtZXMobnRfZ2VuZXNldCksIG50X2dlbmVzZXRbLCJSYW5rIl0pCmNvbG5hbWVzKGdlbmVzZXRfcmFua3MpIDwtIGMoIkdlbmVOYW1lIiwgIlJhbmsiKQoKcmFua2VkX2dlbmVzZXRfZmlsZXBhdGggPC0gZmlsZS5wYXRoKGdldHdkKCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvX2lkLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJhZ19yYW5rcy5ybmsiKQojIGlmIHRoZSBmaWxlIGRvZXMgbm90IGV4aXN0IGFscmVhZHkKaWYgKCFmaWxlLmV4aXN0cyhyYW5rZWRfZ2VuZXNldF9maWxlcGF0aCkpIHsKICAjIHdyaXRlIHRoaXMgbWF0cml4IHRvIHRoZSBmaWxlCiAgd3JpdGUudGFibGUoZ2VuZXNldF9yYW5rcywKICAgICAgICAgICAgICByYW5rZWRfZ2VuZXNldF9maWxlcGF0aCwKICAgICAgICAgICAgICBxdW90ZT1GQUxTRSxzZXA9Ilx0Iixyb3cubmFtZT1GQUxTRSkKfQoKIyBmb3IgdGhlIEVSIG92ZXItZXhwcmVzc2lvbiBtb2RlbAojIGNyZWF0ZSBhIHNlcGFyYXRlIHJhbmtzIG1hdHJpeCB3aXRoIG9ubHkgZ2VuZSBuYW1lIGFuZCByYW5rCmdlbmVzZXRfZXJfcmFua3MgPC0gY2JpbmQocm93bmFtZXMoZXJfZ2VuZXNldCksIGVyX2dlbmVzZXRbLCJSYW5rIl0pCmNvbG5hbWVzKGdlbmVzZXRfZXJfcmFua3MpIDwtIGMoIkdlbmVOYW1lIiwgIlJhbmsiKQoKcmFua2VkX2VyX2dlbmVzZXRfZmlsZXBhdGggPC0gZmlsZS5wYXRoKGdldHdkKCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvX2lkLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJlcl9yYW5rcy5ybmsiKQojIGlmIHRoZSBmaWxlIGRvZXMgbm90IGV4aXN0IGFscmVhZHkKaWYgKCFmaWxlLmV4aXN0cyhyYW5rZWRfZXJfZ2VuZXNldF9maWxlcGF0aCkpIHsKICAjIHdyaXRlIHRoaXMgbWF0cml4IHRvIHRoZSBmaWxlCiAgd3JpdGUudGFibGUoZ2VuZXNldF9lcl9yYW5rcywKICAgICAgICAgICAgICByYW5rZWRfZXJfZ2VuZXNldF9maWxlcGF0aCwKICAgICAgICAgICAgICBxdW90ZT1GQUxTRSxzZXA9Ilx0Iixyb3cubmFtZT1GQUxTRSkKfQpgYGAKCmBgYHtyLCBlY2hvPUZBTFNFLCByZXN1bHRzPSdhc2lzJ30KaGVhZChnZW5lc2V0X3JhbmtzKSAlPiUKICBrbml0cjo6a2FibGUoY2FwdGlvbj0iVGFibGUgMjogR2VuZSBSYW5rcyBmb3IgYWdncmVnYXRlIG1vZGVsIGRlc2lnbiBhY3Jvc3MgSEVSMisvRVIrLCBIRVIyKywgRVIrLCBhbmQgVE5CQyBjbGluaWNhbCBzdWJ0eXBlcyBvZiBicmVhc3QgY2FuY2VyLiIsIGRpZ2l0cz00KSAlPiUKICBrYWJsZV9zdHlsaW5nKCkKYGBgCgpgYGB7ciwgZWNobz1GQUxTRSwgcmVzdWx0cz0nYXNpcyd9CmhlYWQoZ2VuZXNldF9lcl9yYW5rcykgJT4lCiAga25pdHI6OmthYmxlKGNhcHRpb249IlRhYmxlIDM6IEdlbmUgUmFua3MgZm9yIHNwbGl0IG1vZGVsIGRlc2lnbiBhY3Jvc3MgRVIgKy8tIG92ZXJleHByZXNzaW9uIGFzIGEgY2xpbmljYWwgc3VidHlwZSBjbGFzc2lmaWVyIG9mIGJyZWFzdCBjYW5jZXIuIiwgZGlnaXRzPTQpICU+JQogIGthYmxlX3N0eWxpbmcoKQpgYGAKClRoZSBmaXJzdCBmaXZlIGdlbmVzIGFyZSBkaXNwbGF5ZWQgaW4gdGhlIHRhYmxlcyBhYm92ZSBmb3IgdGhlIHR3byBtb2RlbCBkZXNpZ25zIG9mIGludGVyZXN0LgoKIyBOb24tVGhyZXNob2xkZWQgR2VuZS1TZXQgRW5yaWNobWVudCBBbmFseXNpcwoKVXNpbmcgdGhlIEdTRUEgY29tbWFuZC1saW5lIGludGVyZmFjZSBgLmphcmAgZm9yIGNvbXBhdGliaWxpdHkgb2YgdXNpbmcgR1NFQSB3aXRoIFIsIHdlIGNhbiBkb3dubG9hZCB0aGUgZGVzaXJlZCBnZW5lLXNldCBmaWxlIGZyb20gdGhlIEJhZGVyIExhYi4KClRoZSBjb2RlIGJlbG93IGlzIGFkYXB0ZWQgZnJvbSBSdXRoIElzc2VybGluIFtAcmlzc2VybGluXS4KCmBgYHtyLCByZXN1bHRzPSdoaWRlJ30KIyB2YXJpYWJsZSBuYW1lcyBmb3IgZWFzaWVyIG1vZGlmaWNhdGlvbgpnc2VhX2phciA9ICJ+L0dTRUFfNC4zLjIvZ3NlYS1jbGkuc2giCndvcmtpbmdfZGlyID0gIn4vcHJvamVjdHMvR1NFMTc2MDc4IgpvdXRwdXRfZGlyID0gIn4vcHJvamVjdHMvR1NFMTc2MDc4L2dzZWEiCmFuYWx5c2lzX25hbWVfYWcgPSAiY2xpbmljYWwgc3VidHlwZXMiCmFuYWx5c2lzX25hbWVfZXIgPSAiRVIgb3Zlci1leHByZXNzaW9uIgphZ19ybmtfZmlsZSA9ICJhZ19yYW5rcy5ybmsiCmVyX3Jua19maWxlID0gImVyX3JhbmtzLnJuayIKCiMgdGhlIE1hcmNoIDFzdCByZWxlYXNlIChsYXRlc3QgYXQgdGhpcyBwb2ludCkKZ210X3VybCA9ICJodHRwOi8vZG93bmxvYWQuYmFkZXJsYWIub3JnL0VNX0dlbmVzZXRzL01hcmNoXzAxXzIwMjUvSHVtYW4vc3ltYm9sLyIKCiN1c2UgdGhlIG5vbi1maWx0ZXJlZCBnbXQKZ210X2ZpbGVzIDwtIGxpc3QuZmlsZXMocGF0aCA9IG91dHB1dF9kaXIsIHBhdHRlcm4gPSAiXFwuZ210IikKaWYgKGxlbmd0aChnbXRfZmlsZXMpID09IDApIHsKICAjIGRvd25sb2FkIHRoZSBkZXNpcmVkIGdlbmUtc2V0IGZpbGUKICBmaWxlbmFtZXMgPSBnZXRVUkwoZ210X3VybCkKICB0YyA9IHRleHRDb25uZWN0aW9uKGZpbGVuYW1lcykKICBjb250ZW50cyA9IHJlYWRMaW5lcyh0YykKICBjbG9zZSh0YykKICAgIAogICMgZmlsdGVyIGJhc2VkIG9uIHRoZSBmb2xsb3dpbmcgc3BlY2lmaWNhdGlvbnM6CiAgIyArIEdlbmUgT250b2xvZ3kgOiBCaW9sb2dpY2FsIFByb2Nlc3NlcyB0ZXJtcywgCiAgIyAgICsgaW5jbHVkZSBBbGwgUGF0aHdheXMKICAjIC0gV2lraVBhdGh3YXlzIChQRk9DUiksIGFuZAogICMgLSBHTyBJRUEgKGVsZWN0cm9uaWMgYW5ub3RhdGlvbnMpCiAgcnggPSBncmVnZXhwcigiKD88PTxhIGhyZWY9XCIpKC4qLkdPQlBfQWxsUGF0aHdheXNfbm9QRk9DUl9ub19HT19pZWEuKi4pKC5nbXQpKD89XCI+KSIsCiAgICAgICAgICAgICAgICAgIGNvbnRlbnRzLCBwZXJsID0gVFJVRSkKICBnbXRfZmlsZSA9IHVubGlzdChyZWdtYXRjaGVzKGNvbnRlbnRzLCByeCkpCiAgCiAgZGVzdF9nbXRfZmlsZSA8LSBmaWxlLnBhdGgob3V0cHV0X2RpciwgZ210X2ZpbGUpCiAgICAKICAjIGlmIHRoZSBnbXQgZmlsZSBoYXMgbm90IGFscmVhZHkgYmVlbiBkb3dubG9hZGVkCiAgaWYoIWZpbGUuZXhpc3RzKGRlc3RfZ210X2ZpbGUpKXsKICAgICMgZG93bmxvYWQgdGhlIHNwZWNpZmllZCByZWxlYXNlIGZyb20gdGhlIFVSTAogICAgZG93bmxvYWQuZmlsZSgKICAgICAgcGFzdGUoZ210X3VybCxnbXRfZmlsZSxzZXA9IiIpLAogICAgICBkZXN0ZmlsZT1kZXN0X2dtdF9maWxlCiAgICApCiAgfSBlbHNlIHsKICAgIGRlc3RfZ210X2ZpbGUgPC0gZ210X2ZpbGVzWzFdCiAgfQp9CmBgYAoKYGBge3IsIHJlc3VsdHM9J2hpZGUnfQojIGdlbmVyYXRlIHRoZSBjb21tYW5kIGZvciB0aGUgYWdncmVnYXRlIGNsaW5pY2FsIHN1YnR5cGUgbW9kZWwKY21kIDwtIHBhc3RlKCIiLCBnc2VhX2phciwKICAgICAgICAgICAgICJHU0VBUHJlUmFua2VkIC1nbXgiLCBkZXN0X2dtdF9maWxlLAogICAgICAgICAgICAgIi1ybmsiICxmaWxlLnBhdGgod29ya2luZ19kaXIsIGFnX3Jua19maWxlKSwgCiAgICAgICAgICAgICAiLWNvbGxhcHNlIGZhbHNlIC1ucGVybSAxMDAwIC1zY29yaW5nX3NjaGVtZSB3ZWlnaHRlZCIsIAogICAgICAgICAgICAgIi1ycHRfbGFiZWwgIiwgYW5hbHlzaXNfbmFtZV9hZywKICAgICAgICAgICAgICIgIC1wbG90X3RvcF94IDIwIC1ybmRfc2VlZCAxMjM0NSAgLXNldF9tYXggMjAwIiwgIAogICAgICAgICAgICAgIiAtc2V0X21pbiAxNSAtemlwX3JlcG9ydCBmYWxzZSAiLAogICAgICAgICAgICAgIiAtb3V0Iiwgb3V0cHV0X2RpciwgCiAgICAgICAgICAgICAiID4gZ3NlYV9vdXRwdXRfYWcudHh0Iiwgc2VwPSIgIikKIyBpZiB0aGUgb3V0cHV0IGZvbGRlciBkb2VzIG5vdCBhbHJlYWR5IGV4aXN0CmlmIChsZW5ndGgobGlzdC5maWxlcyhwYXRoPW91dHB1dF9kaXIsCiAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuPSJeY2xpbmljYWwuR3NlYVByZXJhbmtlZCIpKSA9PSAwKSB7CiAgc3lzdGVtKGNtZCkgIyBydW4gdGhlIGNtZAp9CgojIGFuZCBnZW5lcmF0ZSB0aGUgY29tbWFuZCBmb3IgdGhlIEVSIG92ZXItZXhwcmVzc2lvbiBjbGFzc2lmaWVyIG1vZGVsCmNtZCA8LSBwYXN0ZSgiIiwgZ3NlYV9qYXIsCiAgICAgICAgICAgICAiR1NFQVByZVJhbmtlZCAtZ214IiwgZGVzdF9nbXRfZmlsZSwKICAgICAgICAgICAgICItcm5rIiAsZmlsZS5wYXRoKHdvcmtpbmdfZGlyLCBlcl9ybmtfZmlsZSksIAogICAgICAgICAgICAgIi1jb2xsYXBzZSBmYWxzZSAtbnBlcm0gMTAwMCAtc2NvcmluZ19zY2hlbWUgd2VpZ2h0ZWQiLCAKICAgICAgICAgICAgICItcnB0X2xhYmVsICIsIGFuYWx5c2lzX25hbWVfZXIsCiAgICAgICAgICAgICAiICAtcGxvdF90b3BfeCAyMCAtcm5kX3NlZWQgMTIzNDUgIC1zZXRfbWF4IDIwMCIsICAKICAgICAgICAgICAgICIgLXNldF9taW4gMTUgLXppcF9yZXBvcnQgZmFsc2UgIiwKICAgICAgICAgICAgICIgLW91dCIsIG91dHB1dF9kaXIsIAogICAgICAgICAgICAgIiA+IGdzZWFfb3V0cHV0X2VyLnR4dCIsIHNlcD0iICIpCiMgaWYgdGhlIG91dHB1dCBmb2xkZXIgZG9lcyBub3QgYWxyZWFkeSBleGlzdAppZiAobGVuZ3RoKGxpc3QuZmlsZXMocGF0aD1vdXRwdXRfZGlyLAogICAgICAgICAgICAgICAgICAgICAgcGF0dGVybj0iXkVSLkdzZWFQcmVyYW5rZWQiKSkgPT0gMCkgewogIHN5c3RlbShjbWQpICMgcnVuIHRoZSBjbWQKfQpgYGAKCiMjIFdoYXQgbWV0aG9kIGRpZCB5b3UgdXNlPwoKSSBjaG9zZSB0byB1c2UgYEdTRUFgJ3MgUHJlUmFua2VkIEFuYWx5c2lzIHNpbmNlIEkgaGFkIGZhbWlsaWFyaXR5IHdpdGggaXQgdGhyb3VnaCBteSBqb3VybmFsIGVudHJ5IGFuZCBmb3VuZCBpdCB0byBiZSB2ZXJ5IGluZm9ybWF0aXZlIG9uIGNvbXBsZXRpb24gb2YgdGhlIGFuYWx5c2lzLiBJdCB3YXMgYWxzbyBmbGV4aWJsZSBpbiB0ZXJtcyBvZiB1c2luZyB3aGljaGV2ZXIgZ2VuZSBtYXRyaXggdHJhbnNwb3NlZCBnZW5lLXNldCBmaWxlIEkgd2FudGVkLCB3aGljaCBtZWFudCBJIGNvdWxkIHJlZG8gdGhlIGFuYWx5c2lzIHByb2dyYW1tYXRpY2FsbHkgaWYgSSBuZWVkZWQgdG8gdHJ5IGFnYWluIHdpdGggYSBkaWZmZXJlbnQgb3IgdXBkYXRlZCBnZW5lLXNldC4KCiMjIyBXaGF0IGdlbmUtc2V0cyBkaWQgeW91IHVzZT8gKFNwZWNpZnkgdmVyc2lvbnMgYW5kIGNpdGUgeW91ciBtZXRob2RzKQoKSSBjaG9zZSB0byB1c2UgdGhlIHRoZSBgSHVtYW5gIGdlbmUtc2V0IGZyb20gdGhlIFtCYWRlckxhYl0oaHR0cHM6Ly9kb3dubG9hZC5iYWRlcmxhYi5vcmcvRU1fR2VuZXNldHMvKSByZWxlYXNlZCBvbiBgTWFyY2ggMXN0LCAyMDI1YC4gVGhlIGdlbmUtc2V0cyB3ZXJlIGRldmVsb3BlZCB1c2luZyB0aGUgbGF0ZXN0IHZlcnNpb24gb2YgR08gSHVtYW4gYW5ub3RhdGlvbnMgb24gRGVjZW1iZXIgMjEsIDIwMjUsIHdoaWNoIG1lYW5zIHdlIGFyZSB1c2luZyB0aGUgcmVsZWFzZSBkYXRlZCBtb3N0IHJlY2VudGx5IGJlZm9yZSB0aGlzLiBBcyBzdWNoLCBpdCBpbmNsdWRlcwoKKiBgR086QlBgIDogYEdlbmUgT250b2xvZ3k6IEJpb2xvZ2ljYWwgUHJvY2Vzc2VzYCA7IAogICAgdmVyc2lvbiBfXzIyNV9fIHJlbGVhc2VkIF9fMjQgT2N0b2JlciwgMjAyNF9fCgpUaGVyZSBpcyBhbiBvcHRpb24gdG8gaW5jbHVkZSBgUEZPQ1JgLCB3aGljaCBpcyBgV2lraVBhdGh3YXlzYCwgaG93ZXZlciBJIGRpZCBub3QgaW5jbHVkZSB0aGlzIHNpbmNlIEkgcGVyZm9ybWVkIHRoZSBhbmFseXNpcyBvbmx5IHVzaW5nIGBHTzpCUGAgZmlyc3QgYW5kIGZvdW5kIGl0IHRvIGJlIHN1ZmZpY2llbnQgZm9yIG15IG5lZWRzIGluIHRlcm1zIG9mIHRoaXMgYW5hbHlzaXMuCgojIyBTdW1tYXJpemUgeW91ciBlbnJpY2htZW50IHJlc3VsdHMKClRoZXJlIGFyZSBhIGxvdCBvZiBpbmRpdmlkdWFsIHBsb3RzIGF2YWlsYWJsZSBmb3Igc3BlY2lmaWMgdGVybXMuCgpGaXJzdCwgdGhlIGZvbGxvd2luZyBwbG90cyBhZ3JlZSB3aXRoIG91ciB2b2xjYW5vIHBsb3RzIHRvIGdpdmUgdXMgbW9yZSBjb25maWRlbmNlIGluIHRoZSByZW1haW5pbmcgcmVzdWx0cy4KCmBgYHtyLCBlY2hvPUZBTFNFLCByZXN1bHRzPSdoaWRlJywgbWVzc2FnZT1GQUxTRX0KIyBzaWRlLWJ5LXNpZGUgcGxvdHRpbmcgZnVuY3Rpb24KcGxvdF9ib3RoIDwtIGZ1bmN0aW9uKGltZzEsIGltZzIsIHRleHQpIHsKICBpbWcxIDwtIGdyaWQ6OnJhc3Rlckdyb2IoYXMucmFzdGVyKHJlYWRQTkcoaW1nMSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBpbnRlcnBvbGF0ZSA9IEZBTFNFKQogIGltZzIgPC0gZ3JpZDo6cmFzdGVyR3JvYihhcy5yYXN0ZXIocmVhZFBORyhpbWcyKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGludGVycG9sYXRlID0gRkFMU0UpCiAgZ3JpZC5hcnJhbmdlKGltZzEsIGltZzIsIG5jb2wgPSAyLCB0b3AgPSB0ZXh0KQp9CmBgYAoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIGVjaG89RkFMU0UsIHJlc3VsdHM9J2FzaXMnfQojIGZpbmQgdGhlIGZvbGRlciBuYW1lcwphZ19kaXIgPC0gZmlsZS5wYXRoKG91dHB1dF9kaXIsIGxpc3QuZmlsZXMocGF0aD1vdXRwdXRfZGlyLAogICAgICAgICAgICAgICAgICAgICAgcGF0dGVybj0iXmNsaW5pY2FsLkdzZWFQcmVyYW5rZWQiKVsxXSkKZXJfZGlyIDwtIGZpbGUucGF0aChvdXRwdXRfZGlyLCBsaXN0LmZpbGVzKHBhdGg9b3V0cHV0X2RpciwKICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm49Il5FUi5Hc2VhUHJlcmFua2VkIilbMV0pCgphZyA8LSBmaWxlLnBhdGgoYWdfZGlyLCAicHZhbHVlc192c19uZXNfcGxvdC5wbmciKQplciA8LSBmaWxlLnBhdGgoZXJfZGlyLCAicHZhbHVlc192c19uZXNfcGxvdC5wbmciKQoKIyBmdW5jdGlvbiBJIGNyZWF0ZWQgdG8gZGlzcGxheSB0d28gcG5nJ3MgaW4gcGFyYWxsZWwKcGxvdF9ib3RoKGFnLCBlciwgIihhKSBBZ2dyZWdhdGUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChiKSBFUiBvdmVyLWV4cHJlc3Npb24iKQpgYGAKCkZpZ3VyZSA1OiBOb3JtYWxpemVkIEVucmljaG1lbnQgU2NvcmUgYW5kIFNpZ25pZmljYW5jZSBwbG90cyBmb3IgYm90aCBtb2RlbCBkZXNpZ25zLiBfX2FfXywgQWdncmVnYXRlIG1vZGVsIGRlc2lnbiwgaWUuIGFjcm9zcyBhbGwgY2xpbmljYWwgc3VidHlwZXMgcHJlc2VudGVkIGluIHRoaXMgc3R1ZHk7ICpIRVIyKyosICpIRVIyKy9FUisqLCAqRVIrKiwgYW5kICpUTkJDKi4gX19iX18sIEVSIG92ZXItZXhwcmVzc2lvbiBzdWJ0eXBlIGNsYXNzaWZpZWQgYnkgZWl0aGVyIG92ZXItZXhwcmVzc2VkICpFUiosIG9yIGxhY2sgdGhlcmVvZi4gUHJvZHVjZWQgYnkgdGhlIEdTRUEgUHJlUmFua2VkIEFuYWx5c2lzLiBTaWduaWZpY2FuY2UgaXMgZGV0ZXJtaW5lZCB2aWEgQmVuamFtaW5pLUhvY2hiZXJnIGNvcnJlY3Rpb24gZm9yIEZhbHNlIERpc2NvdmVyeSBSYXRlLCAqcCA8IDAuMDUqLgoKPGJyLz4KCkkgcmVhZCBpbiB0aGUgcmVzdWx0aW5nIGNzdiBmaWxlcyBmcm9tIHRoZSBHU0VBIHJlcG9ydHMuCgpgYGB7cn0KYWdfbmVnIDwtIHJlYWQuY3N2MihmaWxlLnBhdGgoYWdfZGlyLCAiZ3NlYV9yZXBvcnRfZm9yX25hX25lZ18xNzQzMzg2Mjg3MTgyLnRzdiIpLAogICAgICAgICAgICAgICAgICAgICAgICBoZWFkZXI9VFJVRSwgc2VwPSJcdCIpCmFnX3BvcyA8LSByZWFkLmNzdjIoZmlsZS5wYXRoKGFnX2RpciwgImdzZWFfcmVwb3J0X2Zvcl9uYV9wb3NfMTc0MzM4NjI4NzE4Mi50c3YiKSwKICAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyPVRSVUUsIHNlcD0iXHQiKQoKZXJfbmVnIDwtIHJlYWQuY3N2MihmaWxlLnBhdGgoZXJfZGlyLCAiZ3NlYV9yZXBvcnRfZm9yX25hX25lZ18xNzQzMzg2NTMyMjc4LnRzdiIpLAogICAgICAgICAgICAgICAgICAgICAgICBoZWFkZXI9VFJVRSwgc2VwPSJcdCIpCmVyX3BvcyA8LSByZWFkLmNzdjIoZmlsZS5wYXRoKGVyX2RpciwgImdzZWFfcmVwb3J0X2Zvcl9uYV9wb3NfMTc0MzM4NjUzMjI3OC50c3YiKSwKICAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyPVRSVUUsIHNlcD0iXHQiKQpgYGAKCkkgZGlzcGxheSB0aGUgdG9wIGhpdHMgZm9yIGJvdGggbW9kZWxzLCBib3RoIHBvc2l0aXZlbHkgYW5kIG5lZ2F0aXZlbHkgY29ycmVsYXRlZC4KCmBgYHtyLCBlY2hvPUZBTFNFLCByZXN1bHRzPSdhc2lzJ30KaGVhZChhZ19uZWckTkFNRSkgJT4lCiAga25pdHI6OmthYmxlKGNhcHRpb249IlRhYmxlIDQ6IE5lZ2F0aXZlbHkgY29ycmVsYXRlZCB0b3AgZ2VuZS1zZXQgaGl0cyBmb3IgYWdncmVnYXRlIG1vZGVsIGRlc2lnbiBhY3Jvc3MgSEVSMissIEhFUjIrL0VSKywgRVIrLCBhbmQgVE5CQy4iLCBkaWdpdHM9NCkgJT4lCiAga2FibGVfc3R5bGluZygpCmBgYAoKYGBge3IsIGVjaG89RkFMU0UsIHJlc3VsdHM9J2FzaXMnfQpoZWFkKGFnX3BvcyROQU1FKSAlPiUKICBrbml0cjo6a2FibGUoY2FwdGlvbj0iVGFibGUgNTogUG9zaXRpdmVseSBjb3JyZWxhdGVkIHRvcCBnZW5lLXNldCBoaXRzIGZvciBhZ2dyZWdhdGUgbW9kZWwgZGVzaWduIGFjcm9zcyBIRVIyKywgSEVSMisvRVIrLCBFUissIGFuZCBUTkJDLiIsIGRpZ2l0cz00KSAlPiUKICBrYWJsZV9zdHlsaW5nKCkKYGBgCgpgYGB7ciwgZWNobz1GQUxTRSwgcmVzdWx0cz0nYXNpcyd9CmhlYWQoZXJfbmVnJE5BTUUpICU+JQogIGtuaXRyOjprYWJsZShjYXB0aW9uPSJUYWJsZSA2OiBOZWdhdGl2ZWx5IGNvcnJlbGF0ZWQgdG9wIGdlbmUtc2V0IGhpdHMgZm9yIEVSIG92ZXItZXhwcmVzc2lvbiBtb2RlbCBkZXNpZ24uIiwgZGlnaXRzPTQpICU+JQogIGthYmxlX3N0eWxpbmcoKQpgYGAKCmBgYHtyLCBlY2hvPUZBTFNFLCByZXN1bHRzPSdhc2lzJ30KaGVhZChlcl9wb3MkTkFNRSkgJT4lCiAga25pdHI6OmthYmxlKGNhcHRpb249IlRhYmxlIDc6IFBvc2l0aXZlbHkgY29ycmVsYXRlZCB0b3AgZ2VuZS1zZXQgaGl0cyBmb3IgRVIgb3Zlci1leHByZXNzaW9uIG1vZGVsIGRlc2lnbi4iLCBkaWdpdHM9NCkgJT4lCiAga2FibGVfc3R5bGluZygpCmBgYAoKKiogU2hvdyBzb21lIGVucmljaG1lbnQgcGxvdHMgb2YgaW50ZXJlc3QhIC4uLgoKCl9fYV9fLCBBZ2dyZWdhdGUgbW9kZWwgZGVzaWduLCBpZS4gYWNyb3NzIGFsbCBjbGluaWNhbCBzdWJ0eXBlcyBwcmVzZW50ZWQgaW4gdGhpcyBzdHVkeTsgKkhFUjIrKiwgKkhFUjIrL0VSKyosICpFUisqLCBhbmQgKlROQkMqLiBfX2JfXywgRVIgb3Zlci1leHByZXNzaW9uIHN1YnR5cGUgY2xhc3NpZmllZCBieSBlaXRoZXIgb3Zlci1leHByZXNzZWQgKkVSKiwgb3IgbGFjayB0aGVyZW9mLiBQcm9kdWNlZCBieSB0aGUgR1NFQSBQcmVSYW5rZWQgQW5hbHlzaXMuIFNpZ25pZmljYW5jZSBpcyBkZXRlcm1pbmVkIHZpYSBCZW5qYW1pbmktSG9jaGJlcmcgY29ycmVjdGlvbiBmb3IgRmFsc2UgRGlzY292ZXJ5IFJhdGUsICpwIDwgMC4wNSouCgpodHRwOi8vbG9jYWxob3N0Ojg3ODcvZmlsZXMvcHJvamVjdHMvR1NFMTc2MDc4L2dzZWEvY2xpbmljYWwuR3NlYVByZXJhbmtlZC4xNzQzMzg2Mjg3MTgyL2VucGxvdF9NQUpPUl9QQVRIV0FZX09GX1JSTkFfUFJPQ0VTU0lOR19JTl9USEVfTlVDTEVPTFVTX0FORF9DWVRPU09MX1JFQUNUT01FX1ItSFNBLTY3OTEyMjYuNV8xLnBuZwoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIGVjaG89RkFMU0UsIHJlc3VsdHM9J2FzaXMnfQphZyA8LSBmaWxlLnBhdGgoYWdfZGlyLCAiZW5wbG90X01BSk9SX1BBVEhXQVlfT0ZfUlJOQV9QUk9DRVNTSU5HX0lOX1RIRV9OVUNMRU9MVVNfQU5EX0NZVE9TT0xfUkVBQ1RPTUVfUi1IU0EtNjc5MTIyNi41XzEucG5nIikKZXIgPC0gZmlsZS5wYXRoKGVyX2RpciwgImVucGxvdF9DRUxMLUNFTExfQURIRVNJT05fTUVESUFURURfQllfQ0FESEVSSU5fR09CUF9HT18wMDQ0MzMxXzMucG5nIikKCnBsb3RfYm90aChhZywgZXIsICIoYSkgQWdncmVnYXRlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoYikgRVIgb3Zlci1leHByZXNzaW9uIikKYGBgCgpGaWd1cmUgNjogU29tZSBlbnJpY2htZW50IHBsb3RzIGZvciBib3RoIG1vZGVsIGRlc2lnbnMuIF9fYV9fLCBBZ2dyZWdhdGUgbW9kZWwgZGVzaWduLCBpZS4gYWNyb3NzIGFsbCBjbGluaWNhbCBzdWJ0eXBlcyBwcmVzZW50ZWQgaW4gdGhpcyBzdHVkeTsgKkhFUjIrKiwgKkhFUjIrL0VSKyosICpFUisqLCBhbmQgKlROQkMqLiBQcmVzZW50ZWQgaXMgdGhlIGVucmljaG1lbnQgcGxvdCBmb3IgclJOQSBwcm9jZXNzaW5nIGluIHRoZSBudWNsZXVzIGFuZCBjeXRvc29sIHJlYWN0b21lLiBfX2JfXywgRVIgb3Zlci1leHByZXNzaW9uIHN1YnR5cGUgY2xhc3NpZmllZCBieSBlaXRoZXIgb3Zlci1leHByZXNzZWQgKkVSKiwgb3IgbGFjayB0aGVyZW9mLiBQcmVzZW50ZWQgaXMgdGhlIGVucmljaG1lbnQgcGxvdCBvZiBjZWxsLWNlbGwgYWRoZXNpb24gbWVkaWF0ZWQgY2FkaGVyaW4gYmluZGluZy4gUHJvZHVjZWQgYnkgdGhlIEdTRUEgUHJlUmFua2VkIEFuYWx5c2lzLiBTdGF0aXN0aWNzIGFuZCBtZXRyaWNzIGFyZSBkZXNjcmliZWQgb24gdGhlIEdTRUEgd2Vic2l0ZS4KCjxici8+CgojIyBIb3cgZG8gdGhlc2UgcmVzdWx0cyBjb21wYXJlIHRvIHRoZSByZXN1bHRzIGZyb20gdGhlIHRocmVzaG9sZGVkIGFuYWx5c2lzIGluIEFzc2lnbm1lbnQgMj8gQ29tcGFyZSBxdWFsaXRhdGl2ZWx5LgoKYEludGVyZmVyb25zYCBhbmQgYGNhZGhlcmluLWJpbmRpbmdgIGFyZSBmYW1pbGlhciB0ZXJtcyBmcm9tIGFzc2lnbm1lbnQgMi4gQWx0aG91Z2ggdGhlIGRlcHRoIG9mIGRldGFpbCB3ZSBhY2hpZXZlZCB3YXMgbXVjaCBsZXNzIGluIGFzc2lnbm1lbnQgMiwgYW5kIG5vdCBvbmx5IHRoYXQsIHdlIGhhZCBsZXNzIHNjb3BlIGR1ZSB0byB0aGUgdGhyZXNob2xkcyBvbiBvdXIgZ2VuZS1zZXRzLiBUaGVyZSBhcmUgc29tZSBzaW1pbGFyaXRpZXMsIGFuZCBzb21lIGRpZmZlcmVuY2VzLCB3aGljaCBpcyB0byBiZSBleHBlY3RlZC4KCiMjIyBJcyB0aGlzIGEgc3RyYWlnaHQgZm9yd2FyZCBjb21wYXJpc29uPyBXaHkgb3IgV2h5IG5vdD8KCk5vLCBzaW5jZSB0aGUgdmVyc2lvbnMgb2YgZGF0YSB3ZSBhcmUgdXNpbmcgaXMgZGlmZmVyZW50LiBBbHNvLCB0aGUgdGhyZXNob2xkZWQgYW5hbHlzaXMgZG9lcyBub3QgY29udGFpbiBhcyBtdWNoIGluZm9ybWF0aW9uLCBhbmQgYWx0aG91Z2ggd2UgaGF2ZSBnZW5lLXNldCBzaXplIGluZm9ybWF0aW9uIGF2YWlsYWJsZSBpbiBvdXIgbm9uLXRocmVzaG9sZGVkIGFuYWx5c2lzIHJlc3VsdHMsIGl0IGlzIG5vdCBzdHJhaWdodC1mb3J3YXJkLgoKIyBWaXN1YWxpemluZyBHZW5lLVNldCBFbnJpY2htZW50IEFuYWx5c2lzIGluIEN5dG9zY2FwZQoKU2ltaWxhcmx5IHRvIG91ciBhbmFseXNpcyB1c2luZyBHU0VBLCB3ZSB3aWxsIHBlcmZvcm0gb3VyIGFuYWx5c2lzIHVzaW5nIEN5dG9zY2FwZSB2aWEgUiBjb2RlLgoKVGhlIGNvZGUgYmVsb3cgaXMgYWRhcHRlZCBmcm9tIFJ1dGggSXNzZXJsaW4gW0ByaXNzZXJsaW5jeXRvXS4KCldlIGVuc3VyZSB0byB1c2UgdGhlIG9yaWdpbmFsIGdlbmUtbWF0cml4IHRyYW5zcG9zZWQgZmlsZSBzbyBhcyBub3QgdG8gaGluZGVyIG91ciBhbmFseXNpcyB3aXRoIHRoZSBmaWx0ZXJpbmcgcHJlc2VudCBpbiB0aGUgb3V0cHV0IGAuZ210YCBmcm9tIGBHU0VBYC4KCmBgYHtyfQojdXNlIHRoZSBub24tZmlsdGVyZWQgZ210CmdtdF9maWxlcyA8LSBsaXN0LmZpbGVzKHBhdGggPSBvdXRwdXRfZGlyLCBwYXR0ZXJuID0gIlxcLmdtdCIpCiMgZ2V0IHRoZSBkZXRhaWxzIG9uIHRoZSBmaWxlcwpkZXRhaWxzID0gZmlsZS5pbmZvKGZpbGUucGF0aChvdXRwdXRfZGlyLGdtdF9maWxlcykpCiMgb3JkZXIgZnJvbSBuZXdlc3QgdG8gb2xkZXN0CmRldGFpbHMgPSBkZXRhaWxzW3dpdGgoZGV0YWlscywgb3JkZXIoYXMuUE9TSVhjdChtdGltZSksZGVjcmVhc2luZyA9IFRSVUUpKSwgXQojdXNlIHRoZSBuZXdlc3QgZmlsZToKZ210X2dzZWFfZmlsZSA8LSByb3cubmFtZXMoZGV0YWlscylbMV0KYGBgCgpgYGB7cn0KYWdfZWRiIDwtIGZpbGUucGF0aChhZ19kaXIsICJlZGIiKQplcl9lZGIgPC0gZmlsZS5wYXRoKGVyX2RpciwgImVkYiIpCgphZ19yZXNfZWRiIDwtIGZpbGUucGF0aChhZ19lZGIsICJyZXN1bHRzLmVkYiIpCmVyX3Jlc19lZGIgPC0gZmlsZS5wYXRoKGVyX2VkYiwgInJlc3VsdHMuZWRiIikKCmFnX3JhbmtzIDwtIGZpbGUucGF0aChhZ19lZGIsICJhZ19yYW5rcy5ybmsiKQplcl9yYW5rcyA8LSBmaWxlLnBhdGgoZXJfZWRiLCAiZXJfcmFua3Mucm5rIikKYGBgCgpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KIyBidWlsZCB0aGUgY2xhc3MgZmlsZSBmb3IgYWdncmVnYXRlIGRlc2lnbgphZ19jbHMgPSAifi9wcm9qZWN0cy9HU0UxNzYwNzgvYWcuY2xzIgppZiAoIWZpbGUuZXhpc3RzKGFnX2NscykpIHsKICAjIG51bSBvZiBzYW1wbGVzIG9mIGVhY2ggY2xhc3MKICBjYXQoYXMuY2hhcmFjdGVyKHN1YnR5cGVfY291bnRzWzE6NCwxXSksc2VwID0gIiAiLGZpbGU9YWdfY2xzLGFwcGVuZD1UUlVFKQogIGNhdCgiXG4iLCBmaWxlPWFnX2NscywgYXBwZW5kPVRSVUUpCiAgIyBuYW1lcyBvZiBlYWNoIGNsYXNzCiAgY2F0KGMoIiMiLCAiSEVSMisiLCAiSEVSMisvRVIrIiwgIlROQkMiLCAiRVIrIiksIHNlcCA9ICIgIixmaWxlPWFnX2NscyxhcHBlbmQ9VFJVRSkKICBjYXQoIlxuIiwgZmlsZT1hZ19jbHMsIGFwcGVuZD1UUlVFKQogICMgb3JkZXJlZCBuYW1lIGZvciBlYWNoIHNhbXBsZQogIGNhdCh0eXBlc19kZiRzdWJ0eXBlLCBzZXAgPSAiICIsZmlsZT1hZ19jbHMsYXBwZW5kPVRSVUUpCiAgY2F0KCJcbiIsIGZpbGU9YWdfY2xzLCBhcHBlbmQ9VFJVRSkKfQpgYGAKCldlIG11c3QgZW5zdXJlIGN5dG9zY2FwZSBpcyBydW5uaW5nIGZvciB0aGUgbmV4dCBzZWN0aW9ucyBvZiBjb2RlLiBJZiBldmVyeXRoaW5nIGlzIHdvcmtpbmcgcHJvcGVybHksIHRoZXJlIHdpbGwgYmUgYSBzdWNjZXNzZnVsIG1lc3NhZ2UgZnJvbSBDeXRvc2NhcGUgYWZ0ZXIgd2UgcGluZyEKCmBgYHtyfQojIGRlZmluZSBkb2NrZXIgYmFzZSB1cmwncwpjdXJyZW50X2Jhc2UgPSAiaG9zdC5kb2NrZXIuaW50ZXJuYWw6MTIzNC92MSIKLmRlZmF1bHRCYXNlVXJsIDwtICJodHRwOi8vaG9zdC5kb2NrZXIuaW50ZXJuYWw6MTIzNC92MSIKCmN5dG9zY2FwZVBpbmcoYmFzZS51cmwgPSBjdXJyZW50X2Jhc2UpCmBgYAoKV2UgYXJlIGN1cnJlbnRseSB1c2luZyBgQ3l0b3NjYXBlYCB2ZXJzaW9uIF9fYHIgY3l0b3NjYXBlVmVyc2lvbkluZm8oYmFzZS51cmwgPSBjdXJyZW50X2Jhc2UpYF9fLgoKYGBge3J9CiMgZnVuY3Rpb24gdG8gdXBsb2FkIGEgbG9jYWwgZmlsZSB0byB0aGUgaG9zdCBtYWNoaW5lCnRvX2N5dG9zY2FwZSA8LSBmdW5jdGlvbihsb2NhbF9wYXRoKSB7CiAgYm5hbWUgPC0gYmFzZW5hbWUobG9jYWxfcGF0aCkKICByIDwtIFBPU1QoCiAgICB1cmwgPSAKcGFzdGUoJ2h0dHA6Ly9ob3N0LmRvY2tlci5pbnRlcm5hbDoxMjM0L2VucmljaG1lbnRtYXAvdGV4dGZpbGV1cGxvYWQ/ZmlsZU5hbWU9JywgCiAgICAgICAgICAgICAgICBibmFtZSwgc2VwPSIiKSwKICAgIGNvbmZpZyA9IGxpc3QoKSwKICAgIGJvZHkgPSBsaXN0KGZpbGUgPSB1cGxvYWRfZmlsZShsb2NhbF9wYXRoKSksCiAgICBlbmNvZGUgPSAibXVsdGlwYXJ0IiwKICAgIGhhbmRsZSA9IE5VTEwKICApCiAgY29udGVudChyLCJwYXJzZWQiKSRwYXRoCn0KYGBgCgpgYGB7cn0KIyBzdGFydGluZyB3aXRoIHRoZSBhZ2dyZWdhdGUgZGVzaWduIG1vZGVsLCAKIyB1cGxvYWQgbG9jYWwgZmlsZXMgYW5kIHJlY29yZCB0aGUgaG9zdCBwYXRoCmFnX3Jlc19lZGIgPC0gdG9fY3l0b3NjYXBlKGFnX3Jlc19lZGIpCmFnX3JhbmtzIDwtIHRvX2N5dG9zY2FwZShhZ19yYW5rcykKZ210IDwtIHRvX2N5dG9zY2FwZShnbXRfZ3NlYV9maWxlKQphZ19jbHMgPC0gdG9fY3l0b3NjYXBlKGFnX2NscykKIyBleHByIGZpbGUgPwoKIyBhbmQgdXBsb2FkIGZpbGVzIGZvciB0aGUgRVIgb3Zlci1leHByZXNzaW9uIG1vZGVsCmVyX3Jlc19lZGIgPC0gdG9fY3l0b3NjYXBlKGVyX3Jlc19lZGIpCmVyX3JhbmtzIDwtIHRvX2N5dG9zY2FwZShlcl9yYW5rcykKYGBgCgojIyBDcmVhdGUgYW4gRW5yaWNobWVudCBtYXAKCmBgYHtyfQpwdmFsIDwtIDAuMDUKcXZhbCA8LSAwLjA1CnNpbSA8LSAwLjM3NQpzaW1fbWV0cmljIDwtICJDT01CSU5FRCIgIyBvciBKQUNDQVJECgphZ19uZXR3b3JrIDwtIHBhc3RlKCJhZ2dyZWdhdGUiLCBwdmFsLCBxdmFsLCBzZXA9Il8iKQoKZW1fY21kID0gcGFzdGUoJ2VucmljaG1lbnRtYXAgYnVpbGQgYW5hbHlzaXNUeXBlPSJnc2VhIiBnbXRGaWxlPScsCiAgICAgICAgICAgICAgICBnbXQsCiAgICAgICAgICAgICAgICAncHZhbHVlPScsIHB2YWwsIAogICAgICAgICAgICAgICAgJ3F2YWx1ZT0nLCBxdmFsLAogICAgICAgICAgICAgICAgJ3NpbWlsYXJpdHljdXRvZmY9Jywgc2ltLAogICAgICAgICAgICAgICAgJ2NvZWZmaWNpZW50cz0nLCBzaW1fbWV0cmljLAogICAgICAgICAgICAgICAgJ3JhbmtzRGF0YXNldDE9JywgYWdfcmFua3MsCiAgICAgICAgICAgICAgICAnZW5yaWNobWVudHNEYXRhc2V0MT0nLCBhZ19yZXNfZWRiLCAKICAgICAgICAgICAgICAgICdmaWx0ZXJCeUV4cHJlc3Npb25zPWZhbHNlJywKICAgICAgICAgICAgICAgICMgJ2V4cHJlc3Npb25EYXRhc2V0MT0nLGV4cHJlc3Npb25fZmlsZV9mdWxscGF0aCwKICAgICAgICAgICAgICAgICdjbGFzc0RhdGFzZXQxPScsIGFnX2NscywKICAgICAgICAgICAgICAgICMgJ2dtdEZpbGU9JywgZ210LAogICAgICAgICAgICAgICAgc2VwPSIgIikKCiMgZmV0Y2ggdGhlIHN1aWQgb2YgdGhlIG5ld2x5IGNyZWF0ZWQgbmV0d29yawphZ19yZXNwIDwtIGNvbW1hbmRzR0VUKGVtX2NtZCwgYmFzZS51cmwgPSBjdXJyZW50X2Jhc2UpCgojIGNoZWNrIGlmIHRoZSBjbWQgd2FzIHN1Y2Nlc3NmdWwgb3IgZmFpbGVkCmlmIChncmVwbChwYXR0ZXJuPSJGYWlsZWQiLCBhZ19yZXNwKSkgewogIHBhc3RlKGFnX3Jlc3ApCn0gZWxzZSB7CiAgYWdfc3VpZCA8LSBhZ19yZXNwCn0KCmN1cnJfbmFtZXMgPC0gZ2V0TmV0d29ya0xpc3QoYmFzZS51cmwgPSBjdXJyZW50X2Jhc2UpCmlmIChhZ19uZXR3b3JrICVpbiUgY3Vycl9uYW1lcykgewogIGFnX25ldHdvcmsgPC0gcGFzdGUoYWdfc3VpZCwgYWdfbmV0d29yaywgc2VwPSJfIikKfQoKcmVzcCA8LSByZW5hbWVOZXR3b3JrKHRpdGxlID0gYWdfbmV0d29yaywKICAgICAgICAgICAgICAgICAgICAgIG5ldHdvcmsgPSBhcy5udW1lcmljKGFnX3N1aWQpLAogICAgICAgICAgICAgICAgICAgICAgYmFzZS51cmwgPSBjdXJyZW50X2Jhc2UpCmBgYAoKQW5kLCBmb3IgdGhlIEVSIG92ZXItZXhwcmVzc2lvbiBtb2RlbCwgSSBjcmVhdGUgYW5vdGhlciBlbnJpY2htZW50IG1hcC4KCmBgYHtyfQpwdmFsIDwtIDAuMDUKcXZhbCA8LSAwLjA1CnNpbSA8LSAwLjM3NQpzaW1fbWV0cmljIDwtICJDT01CSU5FRCIgIyBvciBKQUNDQVJECgplcl9uZXR3b3JrIDwtIHBhc3RlKCJlciIsIHB2YWwsIHF2YWwsIHNlcD0iXyIpCgplbV9jbWQgPSBwYXN0ZSgnZW5yaWNobWVudG1hcCBidWlsZCBhbmFseXNpc1R5cGU9ImdzZWEiIGdtdEZpbGU9JywKICAgICAgICAgICAgICAgIGdtdCwKICAgICAgICAgICAgICAgICdwdmFsdWU9JywgcHZhbCwgCiAgICAgICAgICAgICAgICAncXZhbHVlPScsIHF2YWwsCiAgICAgICAgICAgICAgICAnc2ltaWxhcml0eWN1dG9mZj0nLCBzaW0sCiAgICAgICAgICAgICAgICAnY29lZmZpY2llbnRzPScsIHNpbV9tZXRyaWMsCiAgICAgICAgICAgICAgICAncmFua3NEYXRhc2V0MT0nLCBlcl9yYW5rcywKICAgICAgICAgICAgICAgICdlbnJpY2htZW50c0RhdGFzZXQxPScsIGVyX3Jlc19lZGIsIAogICAgICAgICAgICAgICAgJ2ZpbHRlckJ5RXhwcmVzc2lvbnM9ZmFsc2UnLAogICAgICAgICAgICAgICAgc2VwPSIgIikKCiMgZmV0Y2ggdGhlIHN1aWQgb2YgdGhlIG5ld2x5IGNyZWF0ZWQgbmV0d29yawplcl9yZXNwIDwtIGNvbW1hbmRzR0VUKGVtX2NtZCwgYmFzZS51cmwgPSBjdXJyZW50X2Jhc2UpCgojIGNoZWNrIGlmIHRoZSBjbWQgd2FzIHN1Y2Nlc3NmdWwgb3IgZmFpbGVkCmlmIChncmVwbChwYXR0ZXJuPSJGYWlsZWQiLCBlcl9yZXNwKSkgewogIHBhc3RlKGVyX3Jlc3ApCn0gZWxzZSB7CiAgZXJfc3VpZCA8LSBlcl9yZXNwCn0KCmN1cnJfbmFtZXMgPC0gZ2V0TmV0d29ya0xpc3QoYmFzZS51cmwgPSBjdXJyZW50X2Jhc2UpCmlmIChlcl9uZXR3b3JrICVpbiUgY3Vycl9uYW1lcykgewogIGVyX25ldHdvcmsgPC0gcGFzdGUoZXJfc3VpZCwgZXJfbmV0d29yaywgc2VwPSJfIikKfQoKZXJfcmVzcCA8LSByZW5hbWVOZXR3b3JrKHRpdGxlID0gZXJfbmV0d29yaywKICAgICAgICAgICAgICAgICAgICAgICAgIG5ldHdvcmsgPSBhcy5udW1lcmljKGVyX3N1aWQpLAogICAgICAgICAgICAgICAgICAgICAgICAgYmFzZS51cmwgPSBjdXJyZW50X2Jhc2UpCmBgYAoKIyMjIEhvdyBtYW55IG5vZGVzIGFuZCBob3cgbWFueSBlZGdlcyBpbiB0aGUgcmVzdWx0aW5nIG1hcD8KCk91ciBlbnJpY2htZW50IG1hcCBuZXR3b3JrIGZvciB0aGUgYWdncmVnYXRlIG1vZGVsIGRlc2lnbiBhY3Jvc3MgYWxsIGZvdXIgY2xpbmljYWwgc3VidHlwZXMgb2YgYnJlYXN0IGNhbmNlciBwcmVzZW50ZWQsICpIRVIyKy9FUisqLCAqSEVSMisqLCAqRVIrKiwgYW5kICpUTkJDKiwgaGFzOgoKKiAqIyBub2RlcyogOiBgMzY0YAoqICojIGVkZ2VzKiA6IGAyNzY4YAoKQW5kIHRoZSBFUiBvdmVyLWV4cHJlc3Npb24gZGVzaWduIGFjcm9zcyAqRVIrLy0qLCBoYXM6CgoqICojIG5vZGVzKiA6IGA4MmAKKiAqIyBlZGdlcyogOiBgMjAxYAoKIyMjIFdoYXQgdGhyZXNob2xkcyB3ZXJlIHVzZWQgdG8gY3JlYXRlIHRoaXMgbWFwPyAobWFrZSBzdXJlIHRvIHJlY29yZCBhbGwgdGhyZXNob2xkcykKCkkgdXNlZCB0aGUgZm9sbG93aW5nIHRocmVzaG9sZHMgZm9yIGJvdGggbmV0d29ya3M6CgoqICpwLXZhbHVlKiA6IGAwLjA1YAoqICpxLXZhbHVlKiA6IGAwLjA1YAoqICpzaW1pbGFyaXR5IHRocmVzaG9sZCogOiBgMC4zNzVgCgpJIHVzZWQgdGhlIGBDT01CSU5FRGAgc2ltaWxhcml0eSBtZXRyaWMgZm9yIHRoZXNlIG1hcHMuCgojIyMgSW5jbHVkZSBhIHNjcmVlbnNob3Qgb2YgeW91ciBuZXR3b3JrIHByaW9yIHRvIG1hbnVhbCBsYXlvdXQuCgpTaG93biBhcmUgdGhlIG5ldHdvcmtzIHByaW9yIHRvIG1hbnVhbCBsYXlvdXQuIE5vdGUgdGhhdCB0aGlzIHNlY3Rpb24gY291bGQgbm90IGJlIHByb2dyYW1tYXRpY2FsbHkgcmV0cmlldmVkIGFuZCBkaXNwbGF5ZWQgZHVlIHRvIHRoZSBsaW1pdGF0aW9ucyBvZiB1c2luZyBDeXRvc2NhcGUgaW4gUiB3aXRoIERvY2tlci4KCkJvdGggbGF5b3V0cyBhcmUgdmVyeSBtZXNzeSBiZWZvcmUgYWRqdXN0bWVudCwgYW5kIHB1cmVseSBmb3IgZGVtb25zdHJhdGl2ZSBwdXJwb3Nlcy4KCiFbRmlndXJlIDc6IEluaXRpYWwgbmV0d29yayBsYXlvdXQgZm9yIGFnZ3JlZ2F0ZSBtb2RlbCBkZXNpZ247ICpIRVIyKyosICpIRVIyKy9FUisqLCAqRVIrKiwgYW5kICpUTkJDKi4gR2VuZXJhdGVkIHVzaW5nIEN5dG9zY2FwZSB2aWEgUkN5My4gcC12YWx1ZSA8IDAuMDUsIHEtdmFsdWUgPCAwLjA1LCBzaW1pbGFyaXR5IHRocmVzaG9sZCA8IDAuMzc1IHdpdGggYSBjb21iaW5lZCBzaW1pbGFyaXR5IG1ldHJpYy5dKC9ob21lL3JzdHVkaW8vcHJvamVjdHMvZmlndXJlcy9pbml0aWFsX25ldHdvcmtfc3MucG5nKQoKPGJyLz4KCiFbRmlndXJlIDg6IEluaXRpYWwgbmV0d29yayBsYXlvdXQgZm9yIEVSIG92ZXItZXhwcmVzc2lvbiBtb2RlbDsgKkVSKy8tKi4gR2VuZXJhdGVkIHVzaW5nIEN5dG9zY2FwZSB2aWEgUkN5My4gcC12YWx1ZSA8IDAuMDUsIHEtdmFsdWUgPCAwLjA1LCBzaW1pbGFyaXR5IHRocmVzaG9sZCA8IDAuMzc1IHdpdGggYSBjb21iaW5lZCBzaW1pbGFyaXR5IG1ldHJpYy5dKC9ob21lL3JzdHVkaW8vcHJvamVjdHMvZmlndXJlcy9lcl9pbml0LnBuZykKCjxici8+CgoKIyMgQW5ub3RhdGUgeW91ciBOZXR3b3JrCgpBbm5vdGF0aW5nIHRoZSBuZXR3b3JrIGlzIHdoZXJlIHRoZSBtYW51YWwgd29yayBiZWdpbnMgYW5kIHRoZSBmaWd1cmVzIHN0YXJ0IHRvIGxvb2sgcmVhZGFibGUuCgojIyMgV2hhdCBwYXJhbWV0ZXJzIGRpZCB5b3UgdXNlIHRvIGFubm90YXRlIHRoZSBuZXR3b3JrPyAobWFrZSBzdXJlIHRvIGxpc3QgdGhlIGRlZmF1bHQgcGFyYW1ldGVycyB5b3UgYXJlIHVzaW5nIGFzIHdlbGwpCgpJIGFkZGVkIGEgY2xhc3MgZmlsZSBpbiB0aGUgR1NFQSBmb3JtYXQgdG8gYWRkIGluZm9ybWF0aW9uIGFib3V0IGVhY2ggc2FtcGxlJ3MgY2xhc3NpZmljYXRpb24gYWNjb3JkaW5nIHRvIHRoZSBhZ2dyZWdhdGUgY2xpbmljYWwgc3VidHlwZSBkZXNpZ24sIGhvd2V2ZXIgSSBkaWQgbm90IHJlYWxseSBzZWUgaXQgcHJlc2VudCBpbiB0aGUgbmV0d29yay4KCkkgdXNlZCB0aGUgYEF1dG9Bbm5vdGF0ZWAgYWRkaXRpb25hbCBhcHBsaWNhdGlvbiB0byBhbm5vdGF0ZSB1c2luZyBgR2VuZS1TZXQgRGVzY3JpcHRpb25zYC4gSSBzZWxlY3RlZCB0aGUgJ0xheW91dCBOZXR3b3JrIHRvIGF2b2lkIGNsdXN0ZXIgb3ZlcmxhcCcgYW5kIGFkanVzdGVkIHNvbWUgb2YgdGhlIGxhYmVscyB0aGF0IHdlcmUgb3ZlcmxhcHBpbmcuCgpUaGUgbm9kZXMgYXJlIGNvbG91ci1zY2FsZWQgYnkgYEZEUiBxLXZhbHVlYCB3aXRoIGRhcmtlci1yZWQgbm9kZXMgaGF2aW5nIHZhbHVlcyBjbG9zZXIgdG8gMC4wMCwgYW5kIGxpZ2h0ZXItcmVkIG5vZGVzIGhhdmluZyB2YWx1ZXMgY2xvc2VyIHRvIDAuMDUuCgpfX0N1dC1PZmYgVmFsdWVzOl9fCgoqIFAtdmFsdWU6IDAuMDUgCiogRkRSIFEtdmFsdWU6IDAuMDUgCiogSmFjY2FyZCBPdmVybGFwIENvbWJpbmVkOiAwLjM3NSAgCiogVGVzdCB1c2VkOiBKYWNjYXJkIE92ZXJsYXAgQ29tYmluZWQgSW5kZXggKGsgY29uc3RhbnQgPSAwLjUpIAoKX19EYXRhIFNldHM6X18KCiogRGF0YXNldCAxIAoqIEdlbmUgU2V0cyBGaWxlOiAuLi4vZW1fZmlsZXVwbG9hZF8xNjEyMDYyMzkxMzIyNTY3MTg5OC9lbV8xMTE2MjI2Nzk3NDQyNzMyNzY5Nl8KSHVtYW5fR09CUF9BbGxQYXRod2F5c19ub1BGT0NSX25vX0dPX2llYV9NYXJjaF8wMV8yMDI1X3N5bWJvbC5nbXQgCiogRGF0YSBGaWxlczogLi4uL2VtX2ZpbGV1cGxvYWRfMTYxMjA2MjM5MTMyMjU2NzE4OTgvZW1fNjIwNTk5MzQ1MjMxMTUxNzYxN19yZXN1bHRzLmVkYiAKKiBSYW5rcyBGaWxlOiAuLi4vZW1fZmlsZXVwbG9hZF8xNjEyMDYyMzkxMzIyNTY3MTg5OC9lbV8xMzkyNTUyOTEwMTAwNjgyNTExMV9hZ19yYW5rcy5ybmsgCiogUG9zaXRpdmUgUGhlbm90eXBlOiBVUCAKKiBOZWdhdGl2ZSBQaGVub3R5cGU6IERPV04gCgojIyBNYWtlIGEgcHVibGljYXRpb24tcmVhZHkgZmlndXJlIHdpdGggcHJvcGVyIGxlZ2VuZHMuCgpUaGUgYW5ub3RhdGlvbnMgcHJlc2VudCBhcmUgYWxyZWFkeSBncm91cGVkIGFuZCBjbGVhcmx5IGhpZ2hsaWdodGVkLiBJIGFkZGVkIGEgbGVnZW5kIHRvIHRoZSB0b3AtbGVmdCBkZW5vdGluZyB0aGUgbm9kZSBjb2xvdXItc2NhbGluZy4gSSBzZWxlY3RlZCB0aGUgJ1B1YmxpY2F0aW9uIFJlYWR5JyBvcHRpb24gYW5kIGl0IHJlbW92ZWQgdGhlIGxhYmVscyBvZiB0aGUgaW5kaXZpZHVhbCBub2RlcyB0aGVtc2VsdmVzLCBzbyB0aGUgZm9jdXMgY2FuIGJlIGRyYXduIHRvIHRoZSBhbm5vdGF0aW9ucy4KCiFbRmlndXJlIDk6IEFubm90YXRlZCBhZ2dyZWdhdGUgbmV0d29yayBsYXlvdXQ7ICpIRVIyKyosICpIRVIyKy9FUisqLCAqRVIrKiwgYW5kICpUTkJDKi4gR2VuZXJhdGVkIHVzaW5nIEN5dG9zY2FwZSB2aWEgUkN5MywgYW5ub3RhdGVkIHVzaW5nIEF1dG9Bbm5vdGF0ZSBhcHBsaWNhdGlvbiBpbiB0aGUgQ3l0b3NjYXBlIGludGVyZmFjZS4gcC12YWx1ZSA8IDAuMDUsIHEtdmFsdWUgPCAwLjA1LCBzaW1pbGFyaXR5IHRocmVzaG9sZCA8IDAuMzc1IHdpdGggYSBjb21iaW5lZCBzaW1pbGFyaXR5IG1ldHJpYy5dKC9ob21lL3JzdHVkaW8vcHJvamVjdHMvZmlndXJlcy9wdWJfYWcucG5nKQoKPGJyLz4KCiFbRmlndXJlIDEwOiBBbm5vdGF0ZWQgRVIgb3Zlci1leHByZXNzaW9uIG5ldHdvcmsgbGF5b3V0OyAqRVIrLy0qLiBHZW5lcmF0ZWQgdXNpbmcgQ3l0b3NjYXBlIHZpYSBSQ3kzLCBhbm5vdGF0ZWQgdXNpbmcgQXV0b0Fubm90YXRlIGFwcGxpY2F0aW9uIGluIHRoZSBDeXRvc2NhcGUgaW50ZXJmYWNlLiBwLXZhbHVlIDwgMC4wNSwgcS12YWx1ZSA8IDAuMDUsIHNpbWlsYXJpdHkgdGhyZXNob2xkIDwgMC4zNzUgd2l0aCBhIGNvbWJpbmVkIHNpbWlsYXJpdHkgbWV0cmljLl0oL2hvbWUvcnN0dWRpby9wcm9qZWN0cy9maWd1cmVzL2VyX3B1Yi5wbmcpCgo8YnIvPgoKVGhlcmUgaXMgYSBtYWpvciBmb2N1cyBvbiB0aGUgY2VudHJhbCBncm91cGluZyB3aXRoIHNvbWUgc3BhcnNlciBub2RlcyBwcmVzZW50IG9uIHRoZSBvdXRza2lydHMgb2YgdGhlIG5ldHdvcmsuIEkgZmlsdGVyZWQgbm9kZXMgdGhhdCBkaWQgbm90IGhhdmUgbW9yZSB0aGFuIDUgY29ubmVjdGlvbnMsIGhvd2V2ZXIgdGhleSBzdGlsbCBzaG93ZWQgdXAgb24gdGhlIGdyYXBoIGRlc3BpdGUgYmVpbmcgaGlnaGxpZ2h0ZWQgZGlmZmVyZW50bHkgaW4gbXkgaW5pdGlhbCBuZXR3b3JrLgoKIyMgQ29sbGFwc2UgeW91ciBuZXR3b3JrIHRvIGEgdGhlbWUgbmV0d29yay4KCkZvciB0aGlzIHNlY3Rpb24sIEkgZ2VuZXJhdGVkIHR3byB0aGVtZWQgbmV0d29ya3MgZm9yIGVhY2ggb2YgdGhlIG1vZGVsIGRlc2lnbnMuCgpGaXJzdCwgSSBnZW5lcmF0ZWQgYSBzdW1tYXJ5IG5ldHdvcmsgdG8gc2hvdyBhIG1vcmUgY29uY2lzZSBhbmQgc2ltcGxlIGRlc2lnbiBoaWdobGlnaHRpbmcgdGhlIG1ham9yIGNvbm5lY3Rpb24gcG9pbnRzIGluIHRoaXMgbmV0d29yay4KCiFbRmlndXJlIDExOiBTdW1tYXJ5IHRoZW1lZCBuZXR3b3JrIGZvciBhZ2dyZWdhdGUgbW9kZWwgZGVzaWduOyAqSEVSMisqLCAqSEVSMisvRVIrKiwgKkVSKyosIGFuZCAqVE5CQyouIEdlbmVyYXRlZCB1c2luZyBDeXRvc2NhcGUgdmlhIFJDeTMsIGNsZWFuZWQgdXNpbmcgQXV0b0Fubm90YXRlIGFwcGxpY2F0aW9uIGluIHRoZSBDeXRvc2NhcGUgaW50ZXJmYWNlIHRvIGdlbmVyYXRlIGEgU3VtbWFyeSBuZXR3b3JrLiBwLXZhbHVlIDwgMC4wNSwgcS12YWx1ZSA8IDAuMDUsIHNpbWlsYXJpdHkgdGhyZXNob2xkIDwgMC4zNzUgd2l0aCBhIGNvbWJpbmVkIHNpbWlsYXJpdHkgbWV0cmljLl0oL2hvbWUvcnN0dWRpby9wcm9qZWN0cy9maWd1cmVzL3N1bW1hcnlfYWcucG5nKQoKPGJyLz4KCk5leHQsIEkgZ2VuZXJhdGVkIGEgY2x1c3RlcmluZyBhdCB0aGUgbW9zdCBnZW5lcmljIGxldmVsIGZvciB0aGUgYWdncmVnYXRlIGRlc2lnbiBuZXR3b3JrLiAKCgohW0ZpZ3VyZSAxMjogR2VuZXJpYyBjbHVzdGVyaW5nIG5ldHdvcmsgZm9yIGFnZ3JlZ2F0ZSBtb2RlbCBkZXNpZ247ICpIRVIyKyosICpIRVIyKy9FUisqLCAqRVIrKiwgYW5kICpUTkJDKi4gR2VuZXJhdGVkIHVzaW5nIEN5dG9zY2FwZSB2aWEgUkN5MywgY2xlYW5lZCB1c2luZyBBdXRvQW5ub3RhdGUgYXBwbGljYXRpb24gaW4gdGhlIEN5dG9zY2FwZSBpbnRlcmZhY2UgdG8gZ2VuZXJhdGUgdGhlIG1vc3QgZ2VuZXJpYyBjbHVzdGVyaW5nIGF2YWlsYWJsZS4gcC12YWx1ZSA8IDAuMDUsIHEtdmFsdWUgPCAwLjA1LCBzaW1pbGFyaXR5IHRocmVzaG9sZCA8IDAuMzc1IHdpdGggYSBjb21iaW5lZCBzaW1pbGFyaXR5IG1ldHJpYy5dKC9ob21lL3JzdHVkaW8vcHJvamVjdHMvZmlndXJlcy9nZW5lcmljX2FnLnBuZykKCgo8YnIvPgoKIVtGaWd1cmUgMTM6IFN1bW1hcnkgY2x1c3RlcmluZyBuZXR3b3JrIGZvciBFUiBvdmVyLWV4cHJlc3Npb24gbW9kZWwgZGVzaWduOyAqRVIrLy0qLiBHZW5lcmF0ZWQgdXNpbmcgQ3l0b3NjYXBlIHZpYSBSQ3kzLCBjbGVhbmVkIHVzaW5nIEF1dG9Bbm5vdGF0ZSBhcHBsaWNhdGlvbiBpbiB0aGUgQ3l0b3NjYXBlIGludGVyZmFjZSB0byBnZW5lcmF0ZSBhIFN1bW1hcnkgbmV0d29yay4gcC12YWx1ZSA8IDAuMDUsIHEtdmFsdWUgPCAwLjA1LCBzaW1pbGFyaXR5IHRocmVzaG9sZCA8IDAuMzc1IHdpdGggYSBjb21iaW5lZCBzaW1pbGFyaXR5IG1ldHJpYy5dKC9ob21lL3JzdHVkaW8vcHJvamVjdHMvZmlndXJlcy9lcl9zdW0ucG5nKQoKPGJyLz4KCiFbRmlndXJlIDE0OiBHZW5lcmljIGNsdXN0ZXJpbmcgbmV0d29yayBmb3IgRVIgb3Zlci1leHByZXNzaW9uIG1vZGVsIGRlc2lnbjsgKkVSKy8tKi4gR2VuZXJhdGVkIHVzaW5nIEN5dG9zY2FwZSB2aWEgUkN5MywgY2xlYW5lZCB1c2luZyBBdXRvQW5ub3RhdGUgYXBwbGljYXRpb24gaW4gdGhlIEN5dG9zY2FwZSBpbnRlcmZhY2UgdG8gZ2VuZXJhdGUgdGhlIG1vc3QgZ2VuZXJpYyBjbHVzdGVyaW5nIGF2YWlsYWJsZS4gcC12YWx1ZSA8IDAuMDUsIHEtdmFsdWUgPCAwLjA1LCBzaW1pbGFyaXR5IHRocmVzaG9sZCA8IDAuMzc1IHdpdGggYSBjb21iaW5lZCBzaW1pbGFyaXR5IG1ldHJpYy5dKC9ob21lL3JzdHVkaW8vcHJvamVjdHMvZmlndXJlcy9lcl9nZW4ucG5nKQoKPGJyLz4KCiMjIyBXaGF0IGFyZSB0aGUgbWFqb3IgdGhlbWVzIHByZXNlbnQgaW4gdGhpcyBhbmFseXNpcz8KClByZXR0eSBjbGVhcmx5IGZvciB0aGUgYWdncmVnYXRlIG1vZGVsIGRlc2lnbiwgdGhlIG1ham9yIHRoZW1lIGlzIHByb3RlaW4gc3ludGhlc2lzIHByb2Nlc3Nlcy4gVGhlIG1vc3QgZ2VuZXJpYyBsZXZlbCBvZiBncm91cGluZyBoYWQgbm8gcmVhbCBlZmZlY3Qgb24gdGhlIG5vZGVzIHNlZW1pbmdseSBzZXBhcmF0ZSBmcm9tIHRoZSBtb3N0IGNlbnRyYWwgZ3JvdXBpbmcsIGFuZCBzbyBncm91cGVkIHRoZSBtb3N0IHJlbGF0ZWQgZ2VuZS1zZXRzIGludG8gYFByb3RlaW4gU3ludGhlc2lzIFByb2Nlc3Nlc2AuCgpUaGlzIHBhcnRpY3VsYXIgZ3JvdXBpbmcgbWFqb3JseSBjb21iaW5lcyBgU1JQIFByb3RlaW4gU3ludGhlc2lzYCwgYE51Y2xlYXIgRXhwb3J0IFN1bW95bGF0aW9uYCwgYFByb2Nlc3MgUHVyaW5lIENhdGFib2xpc21gLCBhbmQgYFN0cmFuZCBETkEgVGVtcGxhdGluZ2AsIGFsb25nIHdpdGggYGRlIG5vdm8gZm9sZGluZ2AsIGBzbWFsbCBzdWJ1bml0IGFzc2VtYmx5YCwgYFRyaWNpc3Ryb25pYyByUk5BIFNTVWAsIGFtb25nIGEgZmV3IG90aGVycy4KCkFwYXJ0IGZyb20gdGhpcyBtYWpvciB0aGVtZSwgdGhlIHNlcGFyYXRlIGdyb3VwcyBhcmUgZmFpcmx5IHNlcGFyYXRlLCBhbHRob3VnaCBzb21lIHBvc3NpYmxlIG1lY2hhbmlzbXMgcHJlc2VudCB0aGVtc2VsdmVzIGFzIGludGVyZXN0aW5nLCBzdWNoIGFzIHRoZSByZWxhdGlvbiBvZiBgVGh5bWljIElMMiAxIFBhdGh3YXlgIGFuZCBgU3BpbmRsZSBDaGVja3BvaW50IENocm9tb3NvbWVgIHRvIGJyZWFzdCBjYW5jZXJvdXMgc3VidHlwZSBkaWZmZXJlbmNlcy4KCjxici8+CgpGb3IgdGhlIEVSIG92ZXItZXhwcmVzc2lvbiBtb2RlbCBkZXNpZ24sIHRoZSBtYWpvciB0aGVtZSBhcHBlYXJzIHRvIGJlIHRoZSBgRWxlY3Ryb24gVHJhbnNwb3J0IFByb2Nlc3NgLCBhbG9uZyB3aXRoIGBQaG9zcGhvbGlwaWQgUGhhZ29jeXRvc2lzYCBhbmQgYFN0cmFuZCBOdWNsZWFyIEROQWAuCgpgRWxlY3Ryb24gVHJhbnNwb3J0IFByb2Nlc3NgIGdyb3VwcyBgR2x5Y29nZW5lc2lzIFR5cGUgRGVmaWNpZW5jeWAsIGBQcm9jZXNzIERpcGhvc3BoYXRlIE1ldGFib2xpY2AsIGFuZCBgQ291cGxlZCBFbGVjdHJvbiBUcmFuc3BvcnRgLgoKIyMjIERvIHRoZXkgZml0IHdpdGggdGhlIG1vZGVsPwoKSXQgaXMgbm90IHZlcnkgaW5mb3JtYXRpdmUgdG8gc2F5IHRoYXQgYFByb3RlaW4gU3ludGhlc2lzIFByb2Nlc3Nlc2AgZml0IGFzIGEgZGV0ZXJtaW5hdGlvbiBpbiBkaXN0aW5ndWlzaGluZyBkaWZmZXJlbnQgY2xpbmljYWwgc3VidHlwZXMgb2YgYnJlYXN0IGNhbmNlci4gKkhFUjIqIGFuZCAqRVIqIG92ZXItZXhwcmVzc2lvbiBvciBsYWNrIHRoZXJlb2YgY2xhc3NpZnkgdGhlc2Ugc3VidHlwZXMsIGFuZCBzbyBpdCBzZWVtcyBuYXR1cmFsIHRoYXQgcHJvdGVpbiBzeW50aGVzaXMgaXMgaW52b2x2ZWQuCgpTaW1pbGFybHksIHRoZSBgRWxlY3Ryb24gVHJhbnNwb3J0IFByb2Nlc3NgIGlzIGhhbGxtYXJrIHRvIHRoZSBlbnRpcmV0eSBvZiBjZWxsdWxhciBmdW5jdGlvbi4gQXMgdG8gaG93IGl0IGZpdHMgd2l0aCAqRVIqIG92ZXItZXhwcmVzc2lvbiBvciBsYWNrIHRoZXJlb2YgaW4gYnJlYXN0IGNhbmNlcm91cyBzdWJ0eXBlcyBpcyB1bmtub3duLgoKIyMjIEFyZSB0aGVyZSBhbnkgbm92ZWwgcGF0aHdheXMgb3IgdGhlbWVzPwoKVGhlcmUgYXJlIHNvbWUgbm92ZWwgcGF0aHdheXMgYW5kIHRoZW1lcywgbGlrZSB0aGF0IG9mIGBUaHltaWMgSUwyIDEgUGF0aHdheWAgYW5kIGBTcGluZGxlIENoZWNrcG9pbnQgQ2hyb21vc29tZWAgd2hpY2ggY2FuIGJlIGFzc29jaWF0ZWQgd2l0aCBwb3NzaWJsZSBtZWNoYW5pc21zIG9mIGJyZWFzdCBjYW5jZXIuIEFzIHRvIGhvdyB0aGVzZSBzZXBhcmF0ZSB0aGUgY2xpbmljYWwgc3VidHlwZXMgb2YgYnJlYXN0IGNhbmNlciBpcyBub3ZlbCwgYnV0IHBvc3NpYmxlLiBJbnRlcmxldWtpbiBpbmZsYW1tYXRpb24gY2FuIGNvbnRyaWJ1dGUgdG8gZW52aXJvbm1lbnRzIGNvbmR1Y2l2ZSB0byBjYW5jZXJvdXMgZ3Jvd3RoIGFuZCBwcm9saWZlcmF0aW9uLCBzaW1pbGFybHkgd2l0aCBwcm9ibGVtcyBpbiB0aGUgY2VsbCBjeWNsZSBsaWtlIHRoYXQgb2Ygc3BpbmRsZSBjaGVja3BvaW50KHMpLgoKYFNraW4gRXBpZGVybWlzIERldmVsb3BtZW50YCBzZWVtcyBxdWl0ZSBmYXIgb2ZmIGZyb20gYnJlYXN0IGNhbmNlci4gSSBhbSBhc3N1bWluZyBtZXRhc3Rhc2VzIGNhbiBiZSBjb21tb24gZm9yIG9uZSByZWFzb24gb3IgYW5vdGhlciwgYnV0IGl0IGlzIHZlcnkgZGlmZmljdWx0IHRvIGNoYXJhY3Rlcml6ZSB0aGlzIHNtYWxsIGdyb3VwaW5nIGFzIGJlaW5nIHJlbGF0ZWQgdG8gdGhlIGNsaW5pY2FsIHN1YnR5cGVzIG9mIG91ciBpbnRlcmVzdC4KCkZvciB0aGUgRVIgb3Zlci1leHByZXNzaW9uLCBpdCBzZWVtcyBtb3N0IG9mIHRoZSBwYXRod2F5cywgZXZlbiBkZXNwaXRlIGhhdmluZyBvbmx5IGEgZmV3IG5vZGVzLCBhcmUgcmF0aGVyIHJlbGV2YW50IHRvIHRoZSByZWxhdGl2ZSByZWFsbSBvZiBicmVhc3QgY2FuY2Vyb3VzIHBhdGhvbG9neS4KCiMgSW50ZXJwcmV0YXRpb24KCiMjIERvIHRoZSBlbnJpY2htZW50IHJlc3VsdHMgc3VwcG9ydCBjb25jbHVzaW9ucyBvciBtZWNoYW5pc21zIGRpc2N1c3NlZCBpbiB0aGUgb3JpZ2luYWwgcGFwZXI/CgpUaGUgb3JpZ2luYWwgcGFwZXIgaW5jbHVkZWQgdGhpcyBlbnJpY2htZW50IGFuYWx5c2lzIG9mIHRoZWlyIHNpbmdsZS1jZWxsIFJOQSBzZXF1ZW5jaW5nIHNhbXBsZXMuIFRoaXMgR2VuZS1TZXQgRW5yaWNobWVudCBBbmFseXNpcyB3YXMgcGVyZm9ybWVkIHVzaW5nIENsdXN0ZXJQcm9maWxlciB3aXRoIGdlbmUtc2V0cyBmcm9tIHRoZSBNU2lnREIgSEFMTE1BUksgY29sbGVjdGlvbi4gKnAtdmFsdWVzIDwgMC4wNSogd2VyZSBhZGp1c3RlZCB1c2luZyBCb25mZXJyb25pLgoKIVtGaWd1cmUgMTU6IEdlbmUtU2V0IEVucmljaG1lbnQgQW5hbHlzaXMgcGVyZm9ybWVkIGJ5IHRoZSBvcmlnaW5hbCBwdWJsaXNoZXJzIFd1LiBldCBhbCAoMjAyMSldKC9ob21lL3JzdHVkaW8vcHJvamVjdHMvZmlndXJlcy9vZ19wYXBlci5wbmcpCgo8YnIvPgoKTXkgYWdncmVnYXRlIG1vZGVsIGRlc2lnbiBzb2xlbHkgYWdyZWVzIHdpdGggdGhlIGZpbmRpbmdzIG9mIHRoZSBwdWJsaWNhdGlvbiBvbiBgTWl0b3RpYyBTcGluZGxlYC4gVGhlIHJlbWFpbmRlciBvZiBteSBuZXR3b3JrIGRvZXMgbm90IGFncmVlIHdpdGggdGhlIGZpbmRpbmdzIHdoYXRzb2V2ZXIuCgpTaW1pbGFybHksIG15IEVSIG92ZXItZXhwcmVzc2lvbiBkZXNpZ24gbGlzdHMgYEhhbGxtYXJrIEludGVyZmVyb24gUmVzcG9uc2VgIGluIGFncmVlbWVudCB3aXRoIHRoZSBwdWJsaWNhdGlvbi4gT3RoZXIgdGhhbiB0aGF0LCB0aGVyZSBpcyBsaXR0bGUgYWdyZWVtZW50LgoKIyMjIEhvdyBkbyB0aGVzZSByZXN1bHRzIGRpZmZlciBmcm9tIHRoZSByZXN1bHRzIHlvdSBnb3QgaW4gQXNzaWdubWVudCAyIHRocmVzaG9sZGVkIG1ldGhvZHM/CgpJbiBhc3NpZ25tZW50IDIsIG15IGVucmljaG1lbnQgcmVzdWx0cyBtZW50aW9uZWQgYEludGVyZmVyb25zYCwgYW5kIGBDYWRoZXJpbi1iaW5kaW5nYCwgYnV0IG5vdGhpbmcgZWxzZSBpcyB0b28gc2ltaWxhci4gQXBhcnQgZnJvbSB0aGUgdmVyeSBnZW5lcmljIGNvbmNsdXNpb25zIGJlaW5nIGBQcm90ZWluIFN5bnRoZXNpcyBQcm9jZXNzZXNgIGFuZCBgRWxlY3Ryb24gVHJhbnNwb3J0IFByb2Nlc3Nlc2AuCgojIyBDYW4geW91IGZpbmQgZXZpZGVuY2UsIGllLiBwdWJsaWNhdGlvbnMsIHRvIHN1cHBvcnQgc29tZSBvZiB0aGUgcmVzdWx0cyB0aGF0IHlvdSBzZWU/CgpOb3QgY29uY2x1c2l2ZWx5LiBBbHRob3VnaCB0aGVyZSBpcyBhbHdheXMgY29ycmVsYXRpdmUgZXZpZGVuY2UsIGVzcGVjaWFsbHkgaW4gYSBmaWVsZCBzbyByZXNlYXJjaGVkIGFzIGJyZWFzdCBjYW5jZXIsIEkgZG8gbm90IGJlbGlldmUgdGhlIGV2aWRlbmNlIGlzIHN1YnN0YW50aWFsIGVub3VnaCB0byByZWFsbHkgc2F5IGFueXRoaW5nIGF0IHRoaXMgcG9pbnQuIFRoZSBuZXR3b3JrIG91dGNvbWVzIGFyZSB0b28gZ2VuZXJpYyBmb3IgYW55IGNvbmNsdXNpb25zIHRvIGJlIGRyYXduIGZyb20gdGhpcy4KCiMjIyBIb3cgZG9lcyB0aGUgZXZpZGVuY2Ugc3VwcG9ydCB5b3VyIHJlc3VsdD8KCkkgc3RydWdnbGVkIHRvIGZpbmQgZXZpZGVuY2UgdG8gc3VwcG9ydCB0aGVzZSByZXN1bHRzIHNpbmNlIHRoZXkgYXJlIHNvIGdlbmVyaWMuCgojIERldGFpbGVkIFZpZXcgb2YgUmVzdWx0cwoKSSBjaG9zZSB0byBhbmFseXplIHRoZSB0aHJlZSBzaWduaWZpY2FudGx5IGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyBpbiB0aGUgRVIgb3Zlci1leHByZXNzaW9uIG1vZGVsOiAqQU5YQTgqLCAqTUtYKiwgYW5kICpDRDIwNyouCgpJIGZvdW5kIGEgbmV0d29yayBjb250YWluaW5nIGJvdGggKkFOWEE4KiBhbmQgKkNEMjA3KiB1bmRlciB0aGUgZXBpZGVybWlzIGRldmVsb3BtZW50IEdPIGJpb2xvZ2ljYWwgcHJvY2Vzcy4KCiFbRmlndXJlIDE2OiBOZXR3b3JrIGZvciBlcGlkZXJtaXMgZGV2ZWxvcG1lbnQgd2hpY2ggaW5jbHVkZXMgYm90aCBBTlhBOCBhbmQgQ0QyMDc7IHR3byBvZiB0aGUgdGhyZWUgc2lnbmlmaWNhbnQgZ2VuZXMgaW4gRVIgb3Zlci1leHByZXNzaW9uLiBQdWxsZWQgYnkgdXNpbmcgdGhlIFNUSVRDSCBwcm90ZWluIHF1ZXJ5IG9uIHRoZSByZXNwZWN0aXZlIGdlbmVzIG9mIGludGVyZXN0IG9uIEN5dG9zY2FwZS5dKC9ob21lL3JzdHVkaW8vcHJvamVjdHMvZmlndXJlcy9leHRyYS5wbmcpCgpUaGV5IGludGVyYWN0IHRocm91Z2ggaHNhLW1pci0yMDUsIHdoaWNoIGlzIGEgbWljcm8gUk5BLiBBY2NvcmRpbmcgdG8gaXRzIGFzc29jaWF0ZWQgZ2VuZSBjYXJkIFtAbWlybmFdLCBpdCBpcyBhc3NvY2lhdGVkIHdpdGggc3F1YW1vdXMgY2VsbCBjYXJjaW5vbWEgaW4gdGhlIGhlYWQgYW5kIG5lY2suIFRoaXMgaXMgYW4gaW50ZXJlc3RpbmcgYXNzb2NpYXRpb24sIGFuZCBub3QgZmFyIG9mZiBmcm9tIGJyZWFzdCBjYW5jZXIsIGFsdGhvdWdoIGEgc3RyZXRjaCBmb3Igc3VyZS4KCkxvb2tpbmcgZnVydGhlciBpbnRvIHNxdWFtb3VzIGJyZWFzdCBjYW5jZXJvdXMgdGlzc3VlcyBicm91Z2h0IG1lIHRvIHRoaXMgU3RyaW5nIG5ldHdvcmsuCgohW0ZpZ3VyZSAxNzogU3RyaW5nIE5ldHdvcmsgZm9yIHNxdWFtb3VzIGNhcmNpbm9tYSBpbiBicmVhc3QgdGlzc3VlLiBQdWxsZWQgYnkgdXNpbmcgdGhlIFNUSVRDSCBkaXNlYXNlIHF1ZXJ5IG9uIHNxdWFtb3VzIGNhcmNpbm9tYS5dKC9ob21lL3JzdHVkaW8vcHJvamVjdHMvZmlndXJlcy9zcWEucG5nKQoKTm90YWJseSwgKkVSQkIyKiBpcyBwcmVzZW50IGluIHllbGxvdy4gVGhpcyBpcyB0aGUgZGVmaW5pdGlvbiBvZiBleHByZXNzaW9uIG9mICpIRVIyKiwgYW5kIHNvIGl0cyByZWxhdGlvbiB0byBzcXVhbW91cyBjYXJjaW5vbWEgaW4gYnJlYXN0IGNhbmNlcm91cyB0aXNzdWUgaXMgdmVyeSBpbnRlcmVzdGluZy4gQWRkaXRpb25hbGx5LCB3ZSBzZWUgQlJDQTEsIGEgY2xhc3NpYywgYW5kIE1VQzEsIHdoaWNoIHdhcyBpbiBvdXIgYWdncmVnYXRlIG1vZGVsIGRlc2lnbi4KCiMgQXNzb2NpYXRlZCBKb3VybmFsIEVudHJ5CgpNeSBhc3NvY2lhdGVkIGpvdXJuYWwgZW50cnkgd2lraSBsaW5rIGZvciB0aGlzIGFzc2lnbm1lbnQgaXMgW2hlcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS9iY2I0MjAtMjAyNS9Bbm5hYmVsbGFfQnJlZ2F6emkvd2lraS9Bc3NpZ25tZW50LTMpLgoKIyBBY2tub3dsZWRnbWVudHMKClRoaXMgcGFwZXIgbWFrZXMgdXNlIG9mIHBhY2thZ2VzIGBrbml0cmAgW0Brbml0cjIwMTVdLCBgQmlvY01hbmFnZXJgIFtAYmlvY21hbmFnZXJdLCBgR0VPcXVlcnlgIFtAUi1HRU9xdWVyeV0sIGBrYWJsZUV4dHJhYCBbQGthYmxlZXh0cmFdLCBgZWRnZVJgIFtAUi1lZGdlUl0sIGBsaW1tYWAgW0BsaW1tYTIwMTVdLCBgQ29tcGxleEhlYXRtYXBgIFtAY29tcGxleGhlYXRtYXBdLCBgY2lyY2xpemVgIFtAY2lyY2xpemVdLCBgZ3Byb2ZpbGVyMmAgW0BncHJvZmlsZXIyXSwgYEdTQWAgW0Bnc2FdLCBgcmN1cmxgIFtAcmN1cmxdLCBgZ2dwbG90MmAgW0BSLWdncGxvdDJdLCBgZ3JpZGAgW0BncmlkXSwgYGdyaWRFeHRyYWAgW0BncmlkRXh0cmFdLCBgcG5nYCBbQHBuZ10sIGBSQ3kzYCBbQHJjeTNdLCAmIGBodHRyYCBbQGh0dHJdLgoKIyBCaWJsaW9ncmFwaHk=